mirror of
https://github.com/PowerShell/openssh-portable.git
synced 2025-07-29 00:34:33 +02:00
upstream commit
remove compat20/compat13/compat15 variables ok markus@ Upstream-ID: 43802c035ceb3fef6c50c400e4ecabf12354691c
This commit is contained in:
parent
99f95ba826
commit
97f4d3083b
523
channels.c
523
channels.c
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: channels.c,v 1.357 2017/02/01 02:59:09 dtucker Exp $ */
|
||||
/* $OpenBSD: channels.c,v 1.358 2017/04/30 23:13:25 djm Exp $ */
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
@ -571,14 +571,6 @@ channel_not_very_much_buffered_data(void)
|
||||
for (i = 0; i < channels_alloc; i++) {
|
||||
c = channels[i];
|
||||
if (c != NULL && c->type == SSH_CHANNEL_OPEN) {
|
||||
#if 0
|
||||
if (!compat20 &&
|
||||
buffer_len(&c->input) > packet_get_maxsize()) {
|
||||
debug2("channel %d: big input buffer %d",
|
||||
c->self, buffer_len(&c->input));
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
if (buffer_len(&c->output) > packet_get_maxsize()) {
|
||||
debug2("channel %d: big output buffer %u > %u",
|
||||
c->self, buffer_len(&c->output),
|
||||
@ -616,8 +608,6 @@ channel_still_open(void)
|
||||
case SSH_CHANNEL_RUNIX_LISTENER:
|
||||
continue;
|
||||
case SSH_CHANNEL_LARVAL:
|
||||
if (!compat20)
|
||||
fatal("cannot happen: SSH_CHANNEL_LARVAL");
|
||||
continue;
|
||||
case SSH_CHANNEL_OPENING:
|
||||
case SSH_CHANNEL_OPEN:
|
||||
@ -627,11 +617,9 @@ channel_still_open(void)
|
||||
return 1;
|
||||
case SSH_CHANNEL_INPUT_DRAINING:
|
||||
case SSH_CHANNEL_OUTPUT_DRAINING:
|
||||
if (!compat13)
|
||||
fatal("cannot happen: OUT_DRAIN");
|
||||
return 1;
|
||||
fatal("cannot happen: OUT_DRAIN");
|
||||
default:
|
||||
fatal("channel_still_open: bad channel type %d", c->type);
|
||||
fatal("%s: bad channel type %d", __func__, c->type);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
}
|
||||
@ -672,11 +660,9 @@ channel_find_open(void)
|
||||
return i;
|
||||
case SSH_CHANNEL_INPUT_DRAINING:
|
||||
case SSH_CHANNEL_OUTPUT_DRAINING:
|
||||
if (!compat13)
|
||||
fatal("cannot happen: OUT_DRAIN");
|
||||
return i;
|
||||
fatal("cannot happen: OUT_DRAIN");
|
||||
default:
|
||||
fatal("channel_find_open: bad channel type %d", c->type);
|
||||
fatal("%s: bad channel type %d", __func__, c->type);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
}
|
||||
@ -895,23 +881,12 @@ channel_pre_connecting(Channel *c, fd_set *readset, fd_set *writeset)
|
||||
FD_SET(c->sock, writeset);
|
||||
}
|
||||
|
||||
static void
|
||||
channel_pre_open_13(Channel *c, fd_set *readset, fd_set *writeset)
|
||||
{
|
||||
if (buffer_len(&c->input) < packet_get_maxsize())
|
||||
FD_SET(c->sock, readset);
|
||||
if (buffer_len(&c->output) > 0)
|
||||
FD_SET(c->sock, writeset);
|
||||
}
|
||||
|
||||
static void
|
||||
channel_pre_open(Channel *c, fd_set *readset, fd_set *writeset)
|
||||
{
|
||||
u_int limit = compat20 ? c->remote_window : packet_get_maxsize();
|
||||
|
||||
if (c->istate == CHAN_INPUT_OPEN &&
|
||||
limit > 0 &&
|
||||
buffer_len(&c->input) < limit &&
|
||||
c->remote_window > 0 &&
|
||||
buffer_len(&c->input) < c->remote_window &&
|
||||
buffer_check_alloc(&c->input, CHAN_RBUF))
|
||||
FD_SET(c->rfd, readset);
|
||||
if (c->ostate == CHAN_OUTPUT_OPEN ||
|
||||
@ -927,8 +902,8 @@ channel_pre_open(Channel *c, fd_set *readset, fd_set *writeset)
|
||||
}
|
||||
}
|
||||
/** XXX check close conditions, too */
|
||||
if (compat20 && c->efd != -1 &&
|
||||
!(c->istate == CHAN_INPUT_CLOSED && c->ostate == CHAN_OUTPUT_CLOSED)) {
|
||||
if (c->efd != -1 && !(c->istate == CHAN_INPUT_CLOSED &&
|
||||
c->ostate == CHAN_OUTPUT_CLOSED)) {
|
||||
if (c->extended_usage == CHAN_EXTENDED_WRITE &&
|
||||
buffer_len(&c->extended) > 0)
|
||||
FD_SET(c->efd, writeset);
|
||||
@ -941,29 +916,6 @@ channel_pre_open(Channel *c, fd_set *readset, fd_set *writeset)
|
||||
/* XXX: What about efd? races? */
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
channel_pre_input_draining(Channel *c, fd_set *readset, fd_set *writeset)
|
||||
{
|
||||
if (buffer_len(&c->input) == 0) {
|
||||
packet_start(SSH_MSG_CHANNEL_CLOSE);
|
||||
packet_put_int(c->remote_id);
|
||||
packet_send();
|
||||
c->type = SSH_CHANNEL_CLOSED;
|
||||
debug2("channel %d: closing after input drain.", c->self);
|
||||
}
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
channel_pre_output_draining(Channel *c, fd_set *readset, fd_set *writeset)
|
||||
{
|
||||
if (buffer_len(&c->output) == 0)
|
||||
chan_mark_dead(c);
|
||||
else
|
||||
FD_SET(c->sock, writeset);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a special state for X11 authentication spoofing. An opened X11
|
||||
* connection (when authentication spoofing is being done) remains in this
|
||||
@ -1038,32 +990,6 @@ x11_open_helper(Buffer *b)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
channel_pre_x11_open_13(Channel *c, fd_set *readset, fd_set *writeset)
|
||||
{
|
||||
int ret = x11_open_helper(&c->output);
|
||||
|
||||
if (ret == 1) {
|
||||
/* Start normal processing for the channel. */
|
||||
c->type = SSH_CHANNEL_OPEN;
|
||||
channel_pre_open_13(c, readset, writeset);
|
||||
} else if (ret == -1) {
|
||||
/*
|
||||
* We have received an X11 connection that has bad
|
||||
* authentication information.
|
||||
*/
|
||||
logit("X11 connection rejected because of wrong authentication.");
|
||||
buffer_clear(&c->input);
|
||||
buffer_clear(&c->output);
|
||||
channel_close_fd(&c->sock);
|
||||
c->sock = -1;
|
||||
c->type = SSH_CHANNEL_CLOSED;
|
||||
packet_start(SSH_MSG_CHANNEL_CLOSE);
|
||||
packet_put_int(c->remote_id);
|
||||
packet_send();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
channel_pre_x11_open(Channel *c, fd_set *readset, fd_set *writeset)
|
||||
{
|
||||
@ -1081,11 +1007,7 @@ channel_pre_x11_open(Channel *c, fd_set *readset, fd_set *writeset)
|
||||
buffer_clear(&c->input);
|
||||
chan_ibuf_empty(c);
|
||||
buffer_clear(&c->output);
|
||||
/* for proto v1, the peer will send an IEOF */
|
||||
if (compat20)
|
||||
chan_write_failed(c);
|
||||
else
|
||||
c->type = SSH_CHANNEL_OPEN;
|
||||
chan_write_failed(c);
|
||||
debug2("X11 closed %d i%d/o%d", c->self, c->istate, c->ostate);
|
||||
}
|
||||
}
|
||||
@ -1449,28 +1371,19 @@ channel_post_x11_listener(Channel *c, fd_set *readset, fd_set *writeset)
|
||||
nc = channel_new("accepted x11 socket",
|
||||
SSH_CHANNEL_OPENING, newsock, newsock, -1,
|
||||
c->local_window_max, c->local_maxpacket, 0, buf, 1);
|
||||
if (compat20) {
|
||||
packet_start(SSH2_MSG_CHANNEL_OPEN);
|
||||
packet_put_cstring("x11");
|
||||
packet_put_int(nc->self);
|
||||
packet_put_int(nc->local_window_max);
|
||||
packet_put_int(nc->local_maxpacket);
|
||||
/* originator ipaddr and port */
|
||||
packet_put_cstring(remote_ipaddr);
|
||||
if (datafellows & SSH_BUG_X11FWD) {
|
||||
debug2("ssh2 x11 bug compat mode");
|
||||
} else {
|
||||
packet_put_int(remote_port);
|
||||
}
|
||||
packet_send();
|
||||
packet_start(SSH2_MSG_CHANNEL_OPEN);
|
||||
packet_put_cstring("x11");
|
||||
packet_put_int(nc->self);
|
||||
packet_put_int(nc->local_window_max);
|
||||
packet_put_int(nc->local_maxpacket);
|
||||
/* originator ipaddr and port */
|
||||
packet_put_cstring(remote_ipaddr);
|
||||
if (datafellows & SSH_BUG_X11FWD) {
|
||||
debug2("ssh2 x11 bug compat mode");
|
||||
} else {
|
||||
packet_start(SSH_SMSG_X11_OPEN);
|
||||
packet_put_int(nc->self);
|
||||
if (packet_get_protocol_flags() &
|
||||
SSH_PROTOFLAG_HOST_IN_FWD_OPEN)
|
||||
packet_put_cstring(buf);
|
||||
packet_send();
|
||||
packet_put_int(remote_port);
|
||||
}
|
||||
packet_send();
|
||||
free(remote_ipaddr);
|
||||
}
|
||||
}
|
||||
@ -1500,46 +1413,35 @@ port_open_helper(Channel *c, char *rtype)
|
||||
free(c->remote_name);
|
||||
c->remote_name = xstrdup(buf);
|
||||
|
||||
if (compat20) {
|
||||
packet_start(SSH2_MSG_CHANNEL_OPEN);
|
||||
packet_put_cstring(rtype);
|
||||
packet_put_int(c->self);
|
||||
packet_put_int(c->local_window_max);
|
||||
packet_put_int(c->local_maxpacket);
|
||||
if (strcmp(rtype, "direct-tcpip") == 0) {
|
||||
/* target host, port */
|
||||
packet_put_cstring(c->path);
|
||||
packet_put_int(c->host_port);
|
||||
} else if (strcmp(rtype, "direct-streamlocal@openssh.com") == 0) {
|
||||
/* target path */
|
||||
packet_put_cstring(c->path);
|
||||
} else if (strcmp(rtype, "forwarded-streamlocal@openssh.com") == 0) {
|
||||
/* listen path */
|
||||
packet_put_cstring(c->path);
|
||||
} else {
|
||||
/* listen address, port */
|
||||
packet_put_cstring(c->path);
|
||||
packet_put_int(local_port);
|
||||
}
|
||||
if (strcmp(rtype, "forwarded-streamlocal@openssh.com") == 0) {
|
||||
/* reserved for future owner/mode info */
|
||||
packet_put_cstring("");
|
||||
} else {
|
||||
/* originator host and port */
|
||||
packet_put_cstring(remote_ipaddr);
|
||||
packet_put_int((u_int)remote_port);
|
||||
}
|
||||
packet_send();
|
||||
} else {
|
||||
packet_start(SSH_MSG_PORT_OPEN);
|
||||
packet_put_int(c->self);
|
||||
packet_start(SSH2_MSG_CHANNEL_OPEN);
|
||||
packet_put_cstring(rtype);
|
||||
packet_put_int(c->self);
|
||||
packet_put_int(c->local_window_max);
|
||||
packet_put_int(c->local_maxpacket);
|
||||
if (strcmp(rtype, "direct-tcpip") == 0) {
|
||||
/* target host, port */
|
||||
packet_put_cstring(c->path);
|
||||
packet_put_int(c->host_port);
|
||||
if (packet_get_protocol_flags() &
|
||||
SSH_PROTOFLAG_HOST_IN_FWD_OPEN)
|
||||
packet_put_cstring(c->remote_name);
|
||||
packet_send();
|
||||
} else if (strcmp(rtype, "direct-streamlocal@openssh.com") == 0) {
|
||||
/* target path */
|
||||
packet_put_cstring(c->path);
|
||||
} else if (strcmp(rtype, "forwarded-streamlocal@openssh.com") == 0) {
|
||||
/* listen path */
|
||||
packet_put_cstring(c->path);
|
||||
} else {
|
||||
/* listen address, port */
|
||||
packet_put_cstring(c->path);
|
||||
packet_put_int(local_port);
|
||||
}
|
||||
if (strcmp(rtype, "forwarded-streamlocal@openssh.com") == 0) {
|
||||
/* reserved for future owner/mode info */
|
||||
packet_put_cstring("");
|
||||
} else {
|
||||
/* originator host and port */
|
||||
packet_put_cstring(remote_ipaddr);
|
||||
packet_put_int((u_int)remote_port);
|
||||
}
|
||||
packet_send();
|
||||
free(remote_ipaddr);
|
||||
free(local_ipaddr);
|
||||
}
|
||||
@ -1649,16 +1551,11 @@ channel_post_auth_listener(Channel *c, fd_set *readset, fd_set *writeset)
|
||||
SSH_CHANNEL_OPENING, newsock, newsock, -1,
|
||||
c->local_window_max, c->local_maxpacket,
|
||||
0, "accepted auth socket", 1);
|
||||
if (compat20) {
|
||||
packet_start(SSH2_MSG_CHANNEL_OPEN);
|
||||
packet_put_cstring("auth-agent@openssh.com");
|
||||
packet_put_int(nc->self);
|
||||
packet_put_int(c->local_window_max);
|
||||
packet_put_int(c->local_maxpacket);
|
||||
} else {
|
||||
packet_start(SSH_SMSG_AGENT_OPEN);
|
||||
packet_put_int(nc->self);
|
||||
}
|
||||
packet_start(SSH2_MSG_CHANNEL_OPEN);
|
||||
packet_put_cstring("auth-agent@openssh.com");
|
||||
packet_put_int(nc->self);
|
||||
packet_put_int(c->local_window_max);
|
||||
packet_put_int(c->local_maxpacket);
|
||||
packet_send();
|
||||
}
|
||||
}
|
||||
@ -1680,17 +1577,11 @@ channel_post_connecting(Channel *c, fd_set *readset, fd_set *writeset)
|
||||
c->self, c->connect_ctx.host, c->connect_ctx.port);
|
||||
channel_connect_ctx_free(&c->connect_ctx);
|
||||
c->type = SSH_CHANNEL_OPEN;
|
||||
if (compat20) {
|
||||
packet_start(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION);
|
||||
packet_put_int(c->remote_id);
|
||||
packet_put_int(c->self);
|
||||
packet_put_int(c->local_window);
|
||||
packet_put_int(c->local_maxpacket);
|
||||
} else {
|
||||
packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
|
||||
packet_put_int(c->remote_id);
|
||||
packet_put_int(c->self);
|
||||
}
|
||||
packet_start(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION);
|
||||
packet_put_int(c->remote_id);
|
||||
packet_put_int(c->self);
|
||||
packet_put_int(c->local_window);
|
||||
packet_put_int(c->local_maxpacket);
|
||||
} else {
|
||||
debug("channel %d: connection failed: %s",
|
||||
c->self, strerror(err));
|
||||
@ -1705,17 +1596,12 @@ channel_post_connecting(Channel *c, fd_set *readset, fd_set *writeset)
|
||||
error("connect_to %.100s port %d: failed.",
|
||||
c->connect_ctx.host, c->connect_ctx.port);
|
||||
channel_connect_ctx_free(&c->connect_ctx);
|
||||
if (compat20) {
|
||||
packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE);
|
||||
packet_put_int(c->remote_id);
|
||||
packet_put_int(SSH2_OPEN_CONNECT_FAILED);
|
||||
if (!(datafellows & SSH_BUG_OPENFAILURE)) {
|
||||
packet_put_cstring(strerror(err));
|
||||
packet_put_cstring("");
|
||||
}
|
||||
} else {
|
||||
packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
|
||||
packet_put_int(c->remote_id);
|
||||
packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE);
|
||||
packet_put_int(c->remote_id);
|
||||
packet_put_int(SSH2_OPEN_CONNECT_FAILED);
|
||||
if (!(datafellows & SSH_BUG_OPENFAILURE)) {
|
||||
packet_put_cstring(strerror(err));
|
||||
packet_put_cstring("");
|
||||
}
|
||||
chan_mark_dead(c);
|
||||
}
|
||||
@ -1749,10 +1635,6 @@ channel_handle_rfd(Channel *c, fd_set *readset, fd_set *writeset)
|
||||
debug2("channel %d: not open", c->self);
|
||||
chan_mark_dead(c);
|
||||
return -1;
|
||||
} else if (compat13) {
|
||||
buffer_clear(&c->output);
|
||||
c->type = SSH_CHANNEL_INPUT_DRAINING;
|
||||
debug2("channel %d: input draining.", c->self);
|
||||
} else {
|
||||
chan_read_failed(c);
|
||||
}
|
||||
@ -1820,7 +1702,7 @@ channel_handle_wfd(Channel *c, fd_set *readset, fd_set *writeset)
|
||||
}
|
||||
#ifdef _AIX
|
||||
/* XXX: Later AIX versions can't push as much data to tty */
|
||||
if (compat20 && c->wfd_isatty)
|
||||
if (c->wfd_isatty)
|
||||
dlen = MIN(dlen, 8*1024);
|
||||
#endif
|
||||
|
||||
@ -1833,17 +1715,13 @@ channel_handle_wfd(Channel *c, fd_set *readset, fd_set *writeset)
|
||||
debug2("channel %d: not open", c->self);
|
||||
chan_mark_dead(c);
|
||||
return -1;
|
||||
} else if (compat13) {
|
||||
buffer_clear(&c->output);
|
||||
debug2("channel %d: input draining.", c->self);
|
||||
c->type = SSH_CHANNEL_INPUT_DRAINING;
|
||||
} else {
|
||||
chan_write_failed(c);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
#ifndef BROKEN_TCGETATTR_ICANON
|
||||
if (compat20 && c->isatty && dlen >= 1 && buf[0] != '\r') {
|
||||
if (c->isatty && dlen >= 1 && buf[0] != '\r') {
|
||||
if (tcgetattr(c->wfd, &tio) == 0 &&
|
||||
!(tio.c_lflag & ECHO) && (tio.c_lflag & ICANON)) {
|
||||
/*
|
||||
@ -1860,7 +1738,7 @@ channel_handle_wfd(Channel *c, fd_set *readset, fd_set *writeset)
|
||||
buffer_consume(&c->output, len);
|
||||
}
|
||||
out:
|
||||
if (compat20 && olen > 0)
|
||||
if (olen > 0)
|
||||
c->local_consumed += olen - buffer_len(&c->output);
|
||||
return 1;
|
||||
}
|
||||
@ -1944,8 +1822,6 @@ channel_post_open(Channel *c, fd_set *readset, fd_set *writeset)
|
||||
{
|
||||
channel_handle_rfd(c, readset, writeset);
|
||||
channel_handle_wfd(c, readset, writeset);
|
||||
if (!compat20)
|
||||
return;
|
||||
channel_handle_efd(c, readset, writeset);
|
||||
channel_check_window(c);
|
||||
}
|
||||
@ -1979,9 +1855,6 @@ channel_post_mux_client(Channel *c, fd_set *readset, fd_set *writeset)
|
||||
u_int need;
|
||||
ssize_t len;
|
||||
|
||||
if (!compat20)
|
||||
fatal("%s: entered with !compat20", __func__);
|
||||
|
||||
if (c->rfd != -1 && !c->mux_pause && FD_ISSET(c->rfd, readset) &&
|
||||
(c->istate == CHAN_INPUT_OPEN ||
|
||||
c->istate == CHAN_INPUT_WAIT_DRAIN)) {
|
||||
@ -2074,26 +1947,15 @@ channel_post_mux_listener(Channel *c, fd_set *readset, fd_set *writeset)
|
||||
nc->flags |= CHAN_LOCAL;
|
||||
}
|
||||
|
||||
/* ARGSUSED */
|
||||
static void
|
||||
channel_post_output_drain_13(Channel *c, fd_set *readset, fd_set *writeset)
|
||||
channel_handler_init(void)
|
||||
{
|
||||
int len;
|
||||
int i;
|
||||
|
||||
/* Send buffered output data to the socket. */
|
||||
if (FD_ISSET(c->sock, writeset) && buffer_len(&c->output) > 0) {
|
||||
len = write(c->sock, buffer_ptr(&c->output),
|
||||
buffer_len(&c->output));
|
||||
if (len <= 0)
|
||||
buffer_clear(&c->output);
|
||||
else
|
||||
buffer_consume(&c->output, len);
|
||||
for (i = 0; i < SSH_CHANNEL_MAX_TYPE; i++) {
|
||||
channel_pre[i] = NULL;
|
||||
channel_post[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
channel_handler_init_20(void)
|
||||
{
|
||||
channel_pre[SSH_CHANNEL_OPEN] = &channel_pre_open;
|
||||
channel_pre[SSH_CHANNEL_X11_OPEN] = &channel_pre_x11_open;
|
||||
channel_pre[SSH_CHANNEL_PORT_LISTENER] = &channel_pre_listener;
|
||||
@ -2120,64 +1982,6 @@ channel_handler_init_20(void)
|
||||
channel_post[SSH_CHANNEL_MUX_CLIENT] = &channel_post_mux_client;
|
||||
}
|
||||
|
||||
static void
|
||||
channel_handler_init_13(void)
|
||||
{
|
||||
channel_pre[SSH_CHANNEL_OPEN] = &channel_pre_open_13;
|
||||
channel_pre[SSH_CHANNEL_X11_OPEN] = &channel_pre_x11_open_13;
|
||||
channel_pre[SSH_CHANNEL_X11_LISTENER] = &channel_pre_listener;
|
||||
channel_pre[SSH_CHANNEL_PORT_LISTENER] = &channel_pre_listener;
|
||||
channel_pre[SSH_CHANNEL_AUTH_SOCKET] = &channel_pre_listener;
|
||||
channel_pre[SSH_CHANNEL_INPUT_DRAINING] = &channel_pre_input_draining;
|
||||
channel_pre[SSH_CHANNEL_OUTPUT_DRAINING] = &channel_pre_output_draining;
|
||||
channel_pre[SSH_CHANNEL_CONNECTING] = &channel_pre_connecting;
|
||||
channel_pre[SSH_CHANNEL_DYNAMIC] = &channel_pre_dynamic;
|
||||
|
||||
channel_post[SSH_CHANNEL_OPEN] = &channel_post_open;
|
||||
channel_post[SSH_CHANNEL_X11_LISTENER] = &channel_post_x11_listener;
|
||||
channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener;
|
||||
channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener;
|
||||
channel_post[SSH_CHANNEL_OUTPUT_DRAINING] = &channel_post_output_drain_13;
|
||||
channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting;
|
||||
channel_post[SSH_CHANNEL_DYNAMIC] = &channel_post_open;
|
||||
}
|
||||
|
||||
static void
|
||||
channel_handler_init_15(void)
|
||||
{
|
||||
channel_pre[SSH_CHANNEL_OPEN] = &channel_pre_open;
|
||||
channel_pre[SSH_CHANNEL_X11_OPEN] = &channel_pre_x11_open;
|
||||
channel_pre[SSH_CHANNEL_X11_LISTENER] = &channel_pre_listener;
|
||||
channel_pre[SSH_CHANNEL_PORT_LISTENER] = &channel_pre_listener;
|
||||
channel_pre[SSH_CHANNEL_AUTH_SOCKET] = &channel_pre_listener;
|
||||
channel_pre[SSH_CHANNEL_CONNECTING] = &channel_pre_connecting;
|
||||
channel_pre[SSH_CHANNEL_DYNAMIC] = &channel_pre_dynamic;
|
||||
|
||||
channel_post[SSH_CHANNEL_X11_LISTENER] = &channel_post_x11_listener;
|
||||
channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener;
|
||||
channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener;
|
||||
channel_post[SSH_CHANNEL_OPEN] = &channel_post_open;
|
||||
channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting;
|
||||
channel_post[SSH_CHANNEL_DYNAMIC] = &channel_post_open;
|
||||
}
|
||||
|
||||
static void
|
||||
channel_handler_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < SSH_CHANNEL_MAX_TYPE; i++) {
|
||||
channel_pre[i] = NULL;
|
||||
channel_post[i] = NULL;
|
||||
}
|
||||
if (compat20)
|
||||
channel_handler_init_20();
|
||||
else if (compat13)
|
||||
channel_handler_init_13();
|
||||
else
|
||||
channel_handler_init_15();
|
||||
}
|
||||
|
||||
/* gc dead channels */
|
||||
static void
|
||||
channel_garbage_collect(Channel *c)
|
||||
@ -2312,16 +2116,9 @@ channel_output_poll(void)
|
||||
* We are only interested in channels that can have buffered
|
||||
* incoming data.
|
||||
*/
|
||||
if (compat13) {
|
||||
if (c->type != SSH_CHANNEL_OPEN &&
|
||||
c->type != SSH_CHANNEL_INPUT_DRAINING)
|
||||
continue;
|
||||
} else {
|
||||
if (c->type != SSH_CHANNEL_OPEN)
|
||||
continue;
|
||||
}
|
||||
if (compat20 &&
|
||||
(c->flags & (CHAN_CLOSE_SENT|CHAN_CLOSE_RCVD))) {
|
||||
if (c->type != SSH_CHANNEL_OPEN)
|
||||
continue;
|
||||
if ((c->flags & (CHAN_CLOSE_SENT|CHAN_CLOSE_RCVD))) {
|
||||
/* XXX is this true? */
|
||||
debug3("channel %d: will not send data after close", c->self);
|
||||
continue;
|
||||
@ -2359,24 +2156,12 @@ channel_output_poll(void)
|
||||
* Send some data for the other side over the secure
|
||||
* connection.
|
||||
*/
|
||||
if (compat20) {
|
||||
if (len > c->remote_window)
|
||||
len = c->remote_window;
|
||||
if (len > c->remote_maxpacket)
|
||||
len = c->remote_maxpacket;
|
||||
} else {
|
||||
if (packet_is_interactive()) {
|
||||
if (len > 1024)
|
||||
len = 512;
|
||||
} else {
|
||||
/* Keep the packets at reasonable size. */
|
||||
if (len > packet_get_maxsize()/2)
|
||||
len = packet_get_maxsize()/2;
|
||||
}
|
||||
}
|
||||
if (len > c->remote_window)
|
||||
len = c->remote_window;
|
||||
if (len > c->remote_maxpacket)
|
||||
len = c->remote_maxpacket;
|
||||
if (len > 0) {
|
||||
packet_start(compat20 ?
|
||||
SSH2_MSG_CHANNEL_DATA : SSH_MSG_CHANNEL_DATA);
|
||||
packet_start(SSH2_MSG_CHANNEL_DATA);
|
||||
packet_put_int(c->remote_id);
|
||||
packet_put_string(buffer_ptr(&c->input), len);
|
||||
packet_send();
|
||||
@ -2384,8 +2169,6 @@ channel_output_poll(void)
|
||||
c->remote_window -= len;
|
||||
}
|
||||
} else if (c->istate == CHAN_INPUT_WAIT_DRAIN) {
|
||||
if (compat13)
|
||||
fatal("cannot happen: istate == INPUT_WAIT_DRAIN for proto 1.3");
|
||||
/*
|
||||
* input-buffer is empty and read-socket shutdown:
|
||||
* tell peer, that we will not send more data: send IEOF.
|
||||
@ -2398,8 +2181,7 @@ channel_output_poll(void)
|
||||
chan_ibuf_empty(c);
|
||||
}
|
||||
/* Send extended data, i.e. stderr */
|
||||
if (compat20 &&
|
||||
!(c->flags & CHAN_EOF_SENT) &&
|
||||
if (!(c->flags & CHAN_EOF_SENT) &&
|
||||
c->remote_window > 0 &&
|
||||
(len = buffer_len(&c->extended)) > 0 &&
|
||||
c->extended_usage == CHAN_EXTENDED_READ) {
|
||||
@ -2738,26 +2520,23 @@ channel_input_data(int type, u_int32_t seq, void *ctxt)
|
||||
* that window updates are sent back. Otherwise the connection might
|
||||
* deadlock.
|
||||
*/
|
||||
if (!compat13 && c->ostate != CHAN_OUTPUT_OPEN) {
|
||||
if (compat20) {
|
||||
c->local_window -= win_len;
|
||||
c->local_consumed += win_len;
|
||||
}
|
||||
if (c->ostate != CHAN_OUTPUT_OPEN) {
|
||||
c->local_window -= win_len;
|
||||
c->local_consumed += win_len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (compat20) {
|
||||
if (win_len > c->local_maxpacket) {
|
||||
logit("channel %d: rcvd big packet %d, maxpack %d",
|
||||
c->self, win_len, c->local_maxpacket);
|
||||
}
|
||||
if (win_len > c->local_window) {
|
||||
logit("channel %d: rcvd too much data %d, win %d",
|
||||
c->self, win_len, c->local_window);
|
||||
return 0;
|
||||
}
|
||||
c->local_window -= win_len;
|
||||
if (win_len > c->local_maxpacket) {
|
||||
logit("channel %d: rcvd big packet %d, maxpack %d",
|
||||
c->self, win_len, c->local_maxpacket);
|
||||
}
|
||||
if (win_len > c->local_window) {
|
||||
logit("channel %d: rcvd too much data %d, win %d",
|
||||
c->self, win_len, c->local_window);
|
||||
return 0;
|
||||
}
|
||||
c->local_window -= win_len;
|
||||
|
||||
if (c->datagram)
|
||||
buffer_put_string(&c->output, data, data_len);
|
||||
else
|
||||
@ -2942,17 +2721,15 @@ channel_input_open_confirmation(int type, u_int32_t seq, void *ctxt)
|
||||
c->remote_id = remote_id;
|
||||
c->type = SSH_CHANNEL_OPEN;
|
||||
|
||||
if (compat20) {
|
||||
c->remote_window = packet_get_int();
|
||||
c->remote_maxpacket = packet_get_int();
|
||||
if (c->open_confirm) {
|
||||
debug2("callback start");
|
||||
c->open_confirm(c->self, 1, c->open_confirm_ctx);
|
||||
debug2("callback done");
|
||||
}
|
||||
debug2("channel %d: open confirm rwindow %u rmax %u", c->self,
|
||||
c->remote_window, c->remote_maxpacket);
|
||||
c->remote_window = packet_get_int();
|
||||
c->remote_maxpacket = packet_get_int();
|
||||
if (c->open_confirm) {
|
||||
debug2("callback start");
|
||||
c->open_confirm(c->self, 1, c->open_confirm_ctx);
|
||||
debug2("callback done");
|
||||
}
|
||||
debug2("channel %d: open confirm rwindow %u rmax %u", c->self,
|
||||
c->remote_window, c->remote_maxpacket);
|
||||
packet_check_eom();
|
||||
return 0;
|
||||
}
|
||||
@ -2992,21 +2769,19 @@ channel_input_open_failure(int type, u_int32_t seq, void *ctxt)
|
||||
if (c->type != SSH_CHANNEL_OPENING)
|
||||
packet_disconnect("Received open failure for "
|
||||
"non-opening channel %d.", id);
|
||||
if (compat20) {
|
||||
reason = packet_get_int();
|
||||
if (!(datafellows & SSH_BUG_OPENFAILURE)) {
|
||||
msg = packet_get_string(NULL);
|
||||
lang = packet_get_string(NULL);
|
||||
}
|
||||
logit("channel %d: open failed: %s%s%s", id,
|
||||
reason2txt(reason), msg ? ": ": "", msg ? msg : "");
|
||||
free(msg);
|
||||
free(lang);
|
||||
if (c->open_confirm) {
|
||||
debug2("callback start");
|
||||
c->open_confirm(c->self, 0, c->open_confirm_ctx);
|
||||
debug2("callback done");
|
||||
}
|
||||
reason = packet_get_int();
|
||||
if (!(datafellows & SSH_BUG_OPENFAILURE)) {
|
||||
msg = packet_get_string(NULL);
|
||||
lang = packet_get_string(NULL);
|
||||
}
|
||||
logit("channel %d: open failed: %s%s%s", id,
|
||||
reason2txt(reason), msg ? ": ": "", msg ? msg : "");
|
||||
free(msg);
|
||||
free(lang);
|
||||
if (c->open_confirm) {
|
||||
debug2("callback start");
|
||||
c->open_confirm(c->self, 0, c->open_confirm_ctx);
|
||||
debug2("callback done");
|
||||
}
|
||||
packet_check_eom();
|
||||
/* Schedule the channel for cleanup/deletion. */
|
||||
@ -3022,9 +2797,6 @@ channel_input_window_adjust(int type, u_int32_t seq, void *ctxt)
|
||||
int id;
|
||||
u_int adjust, tmp;
|
||||
|
||||
if (!compat20)
|
||||
return 0;
|
||||
|
||||
/* Get the channel number and verify it. */
|
||||
id = packet_get_int();
|
||||
c = channel_lookup(id);
|
||||
@ -3581,49 +3353,24 @@ channel_rfwd_bind_host(const char *listen_host)
|
||||
int
|
||||
channel_request_remote_forwarding(struct Forward *fwd)
|
||||
{
|
||||
int type, success = 0, idx = -1;
|
||||
int success = 0, idx = -1;
|
||||
|
||||
/* Send the forward request to the remote side. */
|
||||
if (compat20) {
|
||||
packet_start(SSH2_MSG_GLOBAL_REQUEST);
|
||||
if (fwd->listen_path != NULL) {
|
||||
packet_put_cstring("streamlocal-forward@openssh.com");
|
||||
packet_put_char(1); /* boolean: want reply */
|
||||
packet_put_cstring(fwd->listen_path);
|
||||
} else {
|
||||
packet_put_cstring("tcpip-forward");
|
||||
packet_put_char(1); /* boolean: want reply */
|
||||
packet_put_cstring(channel_rfwd_bind_host(fwd->listen_host));
|
||||
packet_put_int(fwd->listen_port);
|
||||
}
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
/* Assume that server accepts the request */
|
||||
success = 1;
|
||||
} else if (fwd->listen_path == NULL) {
|
||||
packet_start(SSH_CMSG_PORT_FORWARD_REQUEST);
|
||||
packet_put_int(fwd->listen_port);
|
||||
packet_put_cstring(fwd->connect_host);
|
||||
packet_put_int(fwd->connect_port);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
|
||||
/* Wait for response from the remote side. */
|
||||
type = packet_read();
|
||||
switch (type) {
|
||||
case SSH_SMSG_SUCCESS:
|
||||
success = 1;
|
||||
break;
|
||||
case SSH_SMSG_FAILURE:
|
||||
break;
|
||||
default:
|
||||
/* Unknown packet */
|
||||
packet_disconnect("Protocol error for port forward request:"
|
||||
"received packet type %d.", type);
|
||||
}
|
||||
packet_start(SSH2_MSG_GLOBAL_REQUEST);
|
||||
if (fwd->listen_path != NULL) {
|
||||
packet_put_cstring("streamlocal-forward@openssh.com");
|
||||
packet_put_char(1); /* boolean: want reply */
|
||||
packet_put_cstring(fwd->listen_path);
|
||||
} else {
|
||||
logit("Warning: Server does not support remote stream local forwarding.");
|
||||
packet_put_cstring("tcpip-forward");
|
||||
packet_put_char(1); /* boolean: want reply */
|
||||
packet_put_cstring(channel_rfwd_bind_host(fwd->listen_host));
|
||||
packet_put_int(fwd->listen_port);
|
||||
}
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
/* Assume that server accepts the request */
|
||||
success = 1;
|
||||
if (success) {
|
||||
/* Record that connection to this host/port is permitted. */
|
||||
permitted_opens = xreallocarray(permitted_opens,
|
||||
@ -3722,9 +3469,6 @@ channel_request_rforward_cancel_tcpip(const char *host, u_short port)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!compat20)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < num_permitted_opens; i++) {
|
||||
if (open_listen_match_tcpip(&permitted_opens[i], host, port, 0))
|
||||
break;
|
||||
@ -3761,9 +3505,6 @@ channel_request_rforward_cancel_streamlocal(const char *path)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!compat20)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < num_permitted_opens; i++) {
|
||||
if (open_listen_match_streamlocal(&permitted_opens[i], path))
|
||||
break;
|
||||
@ -4644,12 +4385,8 @@ x11_request_forwarding_with_spoofing(int client_session_id, const char *disp,
|
||||
new_data = tohex(x11_fake_data, data_len);
|
||||
|
||||
/* Send the request packet. */
|
||||
if (compat20) {
|
||||
channel_request_start(client_session_id, "x11-req", want_reply);
|
||||
packet_put_char(0); /* XXX bool single connection */
|
||||
} else {
|
||||
packet_start(SSH_CMSG_X11_REQUEST_FORWARDING);
|
||||
}
|
||||
channel_request_start(client_session_id, "x11-req", want_reply);
|
||||
packet_put_char(0); /* XXX bool single connection */
|
||||
packet_put_cstring(proto);
|
||||
packet_put_cstring(new_data);
|
||||
packet_put_int(screen_number);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: channels.h,v 1.121 2017/02/01 02:59:09 dtucker Exp $ */
|
||||
/* $OpenBSD: channels.h,v 1.122 2017/04/30 23:13:25 djm Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
@ -200,11 +200,11 @@ struct Channel {
|
||||
|
||||
/* check whether 'efd' is still in use */
|
||||
#define CHANNEL_EFD_INPUT_ACTIVE(c) \
|
||||
(compat20 && c->extended_usage == CHAN_EXTENDED_READ && \
|
||||
(c->extended_usage == CHAN_EXTENDED_READ && \
|
||||
(c->efd != -1 || \
|
||||
buffer_len(&c->extended) > 0))
|
||||
#define CHANNEL_EFD_OUTPUT_ACTIVE(c) \
|
||||
(compat20 && c->extended_usage == CHAN_EXTENDED_WRITE && \
|
||||
(c->extended_usage == CHAN_EXTENDED_WRITE && \
|
||||
c->efd != -1 && (!(c->flags & (CHAN_EOF_RCVD|CHAN_CLOSE_RCVD)) || \
|
||||
buffer_len(&c->extended) > 0))
|
||||
|
||||
|
542
clientloop.c
542
clientloop.c
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: clientloop.c,v 1.291 2017/03/10 05:01:13 djm Exp $ */
|
||||
/* $OpenBSD: clientloop.c,v 1.292 2017/04/30 23:13:25 djm Exp $ */
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
@ -207,15 +207,6 @@ leave_non_blocking(void)
|
||||
}
|
||||
}
|
||||
|
||||
/* Puts stdin terminal in non-blocking mode. */
|
||||
|
||||
static void
|
||||
enter_non_blocking(void)
|
||||
{
|
||||
in_non_blocking_mode = 1;
|
||||
set_nonblock(fileno(stdin));
|
||||
}
|
||||
|
||||
/*
|
||||
* Signal handler for the window change signal (SIGWINCH). This just sets a
|
||||
* flag indicating that the window has changed.
|
||||
@ -454,91 +445,6 @@ client_x11_get_proto(const char *display, const char *xauth_path,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is called when the interactive is entered. This checks if there is
|
||||
* an EOF coming on stdin. We must check this explicitly, as select() does
|
||||
* not appear to wake up when redirecting from /dev/null.
|
||||
*/
|
||||
|
||||
static void
|
||||
client_check_initial_eof_on_stdin(void)
|
||||
{
|
||||
int len;
|
||||
char buf[1];
|
||||
|
||||
/*
|
||||
* If standard input is to be "redirected from /dev/null", we simply
|
||||
* mark that we have seen an EOF and send an EOF message to the
|
||||
* server. Otherwise, we try to read a single character; it appears
|
||||
* that for some files, such /dev/null, select() never wakes up for
|
||||
* read for this descriptor, which means that we never get EOF. This
|
||||
* way we will get the EOF if stdin comes from /dev/null or similar.
|
||||
*/
|
||||
if (stdin_null_flag) {
|
||||
/* Fake EOF on stdin. */
|
||||
debug("Sending eof.");
|
||||
stdin_eof = 1;
|
||||
packet_start(SSH_CMSG_EOF);
|
||||
packet_send();
|
||||
} else {
|
||||
enter_non_blocking();
|
||||
|
||||
/* Check for immediate EOF on stdin. */
|
||||
len = read(fileno(stdin), buf, 1);
|
||||
if (len == 0) {
|
||||
/*
|
||||
* EOF. Record that we have seen it and send
|
||||
* EOF to server.
|
||||
*/
|
||||
debug("Sending eof.");
|
||||
stdin_eof = 1;
|
||||
packet_start(SSH_CMSG_EOF);
|
||||
packet_send();
|
||||
} else if (len > 0) {
|
||||
/*
|
||||
* Got data. We must store the data in the buffer,
|
||||
* and also process it as an escape character if
|
||||
* appropriate.
|
||||
*/
|
||||
if ((u_char) buf[0] == escape_char1)
|
||||
escape_pending1 = 1;
|
||||
else
|
||||
buffer_append(&stdin_buffer, buf, 1);
|
||||
}
|
||||
leave_non_blocking();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Make packets from buffered stdin data, and buffer them for sending to the
|
||||
* connection.
|
||||
*/
|
||||
|
||||
static void
|
||||
client_make_packets_from_stdin_data(void)
|
||||
{
|
||||
u_int len;
|
||||
|
||||
/* Send buffered stdin data to the server. */
|
||||
while (buffer_len(&stdin_buffer) > 0 &&
|
||||
packet_not_very_much_data_to_write()) {
|
||||
len = buffer_len(&stdin_buffer);
|
||||
/* Keep the packets at reasonable size. */
|
||||
if (len > packet_get_maxsize())
|
||||
len = packet_get_maxsize();
|
||||
packet_start(SSH_CMSG_STDIN_DATA);
|
||||
packet_put_string(buffer_ptr(&stdin_buffer), len);
|
||||
packet_send();
|
||||
buffer_consume(&stdin_buffer, len);
|
||||
/* If we have a pending EOF, send it now. */
|
||||
if (stdin_eof && buffer_len(&stdin_buffer) == 0) {
|
||||
packet_start(SSH_CMSG_EOF);
|
||||
packet_send();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks if the client window has changed, and sends a packet about it to
|
||||
* the server if so. The actual change is detected elsewhere (by a software
|
||||
@ -549,27 +455,14 @@ client_make_packets_from_stdin_data(void)
|
||||
static void
|
||||
client_check_window_change(void)
|
||||
{
|
||||
struct winsize ws;
|
||||
|
||||
if (! received_window_change_signal)
|
||||
if (!received_window_change_signal)
|
||||
return;
|
||||
/** XXX race */
|
||||
received_window_change_signal = 0;
|
||||
|
||||
debug2("client_check_window_change: changed");
|
||||
debug2("%s: changed", __func__);
|
||||
|
||||
if (compat20) {
|
||||
channel_send_window_changes();
|
||||
} else {
|
||||
if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0)
|
||||
return;
|
||||
packet_start(SSH_CMSG_WINDOW_SIZE);
|
||||
packet_put_int((u_int)ws.ws_row);
|
||||
packet_put_int((u_int)ws.ws_col);
|
||||
packet_put_int((u_int)ws.ws_xpixel);
|
||||
packet_put_int((u_int)ws.ws_ypixel);
|
||||
packet_send();
|
||||
}
|
||||
channel_send_window_changes();
|
||||
}
|
||||
|
||||
static int
|
||||
@ -623,35 +516,15 @@ client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp,
|
||||
channel_prepare_select(readsetp, writesetp, maxfdp, nallocp,
|
||||
&minwait_secs, rekeying);
|
||||
|
||||
if (!compat20) {
|
||||
/* Read from the connection, unless our buffers are full. */
|
||||
if (buffer_len(&stdout_buffer) < buffer_high &&
|
||||
buffer_len(&stderr_buffer) < buffer_high &&
|
||||
channel_not_very_much_buffered_data())
|
||||
FD_SET(connection_in, *readsetp);
|
||||
/*
|
||||
* Read from stdin, unless we have seen EOF or have very much
|
||||
* buffered data to send to the server.
|
||||
*/
|
||||
if (!stdin_eof && packet_not_very_much_data_to_write())
|
||||
FD_SET(fileno(stdin), *readsetp);
|
||||
|
||||
/* Select stdout/stderr if have data in buffer. */
|
||||
if (buffer_len(&stdout_buffer) > 0)
|
||||
FD_SET(fileno(stdout), *writesetp);
|
||||
if (buffer_len(&stderr_buffer) > 0)
|
||||
FD_SET(fileno(stderr), *writesetp);
|
||||
/* channel_prepare_select could have closed the last channel */
|
||||
if (session_closed && !channel_still_open() &&
|
||||
!packet_have_data_to_write()) {
|
||||
/* clear mask since we did not call select() */
|
||||
memset(*readsetp, 0, *nallocp);
|
||||
memset(*writesetp, 0, *nallocp);
|
||||
return;
|
||||
} else {
|
||||
/* channel_prepare_select could have closed the last channel */
|
||||
if (session_closed && !channel_still_open() &&
|
||||
!packet_have_data_to_write()) {
|
||||
/* clear mask since we did not call select() */
|
||||
memset(*readsetp, 0, *nallocp);
|
||||
memset(*writesetp, 0, *nallocp);
|
||||
return;
|
||||
} else {
|
||||
FD_SET(connection_in, *readsetp);
|
||||
}
|
||||
FD_SET(connection_in, *readsetp);
|
||||
}
|
||||
|
||||
/* Select server connection if have data to write to the server. */
|
||||
@ -665,11 +538,11 @@ client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp,
|
||||
*/
|
||||
|
||||
timeout_secs = INT_MAX; /* we use INT_MAX to mean no timeout */
|
||||
if (options.server_alive_interval > 0 && compat20) {
|
||||
if (options.server_alive_interval > 0) {
|
||||
timeout_secs = options.server_alive_interval;
|
||||
server_alive_time = now + options.server_alive_interval;
|
||||
}
|
||||
if (options.rekey_interval > 0 && compat20 && !rekeying)
|
||||
if (options.rekey_interval > 0 && !rekeying)
|
||||
timeout_secs = MINIMUM(timeout_secs, packet_get_rekey_timeout());
|
||||
set_control_persist_exit_time();
|
||||
if (control_persist_exit_time > 0) {
|
||||
@ -966,11 +839,6 @@ process_cmdline(void)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (delete && !compat20) {
|
||||
logit("Not supported for SSH protocol version 1.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
while (isspace((u_char)*++s))
|
||||
;
|
||||
|
||||
@ -1027,10 +895,9 @@ out:
|
||||
|
||||
/* reasons to suppress output of an escape command in help output */
|
||||
#define SUPPRESS_NEVER 0 /* never suppress, always show */
|
||||
#define SUPPRESS_PROTO1 1 /* don't show in protocol 1 sessions */
|
||||
#define SUPPRESS_MUXCLIENT 2 /* don't show in mux client sessions */
|
||||
#define SUPPRESS_MUXMASTER 4 /* don't show in mux master sessions */
|
||||
#define SUPPRESS_SYSLOG 8 /* don't show when logging to syslog */
|
||||
#define SUPPRESS_MUXCLIENT 1 /* don't show in mux client sessions */
|
||||
#define SUPPRESS_MUXMASTER 2 /* don't show in mux master sessions */
|
||||
#define SUPPRESS_SYSLOG 4 /* don't show when logging to syslog */
|
||||
struct escape_help_text {
|
||||
const char *cmd;
|
||||
const char *text;
|
||||
@ -1040,9 +907,9 @@ static struct escape_help_text esc_txt[] = {
|
||||
{".", "terminate session", SUPPRESS_MUXMASTER},
|
||||
{".", "terminate connection (and any multiplexed sessions)",
|
||||
SUPPRESS_MUXCLIENT},
|
||||
{"B", "send a BREAK to the remote system", SUPPRESS_PROTO1},
|
||||
{"B", "send a BREAK to the remote system", SUPPRESS_NEVER},
|
||||
{"C", "open a command line", SUPPRESS_MUXCLIENT},
|
||||
{"R", "request rekey", SUPPRESS_PROTO1},
|
||||
{"R", "request rekey", SUPPRESS_NEVER},
|
||||
{"V/v", "decrease/increase verbosity (LogLevel)", SUPPRESS_MUXCLIENT},
|
||||
{"^Z", "suspend ssh", SUPPRESS_MUXCLIENT},
|
||||
{"#", "list forwarded connections", SUPPRESS_NEVER},
|
||||
@ -1052,8 +919,7 @@ static struct escape_help_text esc_txt[] = {
|
||||
};
|
||||
|
||||
static void
|
||||
print_escape_help(Buffer *b, int escape_char, int protocol2, int mux_client,
|
||||
int using_stderr)
|
||||
print_escape_help(Buffer *b, int escape_char, int mux_client, int using_stderr)
|
||||
{
|
||||
unsigned int i, suppress_flags;
|
||||
char string[1024];
|
||||
@ -1062,7 +928,7 @@ print_escape_help(Buffer *b, int escape_char, int protocol2, int mux_client,
|
||||
"Supported escape sequences:\r\n", escape_char);
|
||||
buffer_append(b, string, strlen(string));
|
||||
|
||||
suppress_flags = (protocol2 ? 0 : SUPPRESS_PROTO1) |
|
||||
suppress_flags =
|
||||
(mux_client ? SUPPRESS_MUXCLIENT : 0) |
|
||||
(mux_client ? 0 : SUPPRESS_MUXMASTER) |
|
||||
(using_stderr ? 0 : SUPPRESS_SYSLOG);
|
||||
@ -1171,26 +1037,20 @@ process_escapes(Channel *c, Buffer *bin, Buffer *bout, Buffer *berr,
|
||||
continue;
|
||||
|
||||
case 'B':
|
||||
if (compat20) {
|
||||
snprintf(string, sizeof string,
|
||||
"%cB\r\n", escape_char);
|
||||
buffer_append(berr, string,
|
||||
strlen(string));
|
||||
channel_request_start(c->self,
|
||||
"break", 0);
|
||||
packet_put_int(1000);
|
||||
packet_send();
|
||||
}
|
||||
snprintf(string, sizeof string,
|
||||
"%cB\r\n", escape_char);
|
||||
buffer_append(berr, string, strlen(string));
|
||||
channel_request_start(c->self, "break", 0);
|
||||
packet_put_int(1000);
|
||||
packet_send();
|
||||
continue;
|
||||
|
||||
case 'R':
|
||||
if (compat20) {
|
||||
if (datafellows & SSH_BUG_NOREKEY)
|
||||
logit("Server does not "
|
||||
"support re-keying");
|
||||
else
|
||||
need_rekeying = 1;
|
||||
}
|
||||
if (datafellows & SSH_BUG_NOREKEY)
|
||||
logit("Server does not "
|
||||
"support re-keying");
|
||||
else
|
||||
need_rekeying = 1;
|
||||
continue;
|
||||
|
||||
case 'V':
|
||||
@ -1248,30 +1108,11 @@ process_escapes(Channel *c, Buffer *bin, Buffer *bout, Buffer *berr,
|
||||
exit(0);
|
||||
}
|
||||
/* The child continues serving connections. */
|
||||
if (compat20) {
|
||||
buffer_append(bin, "\004", 1);
|
||||
/* fake EOF on stdin */
|
||||
return -1;
|
||||
} else if (!stdin_eof) {
|
||||
/*
|
||||
* Sending SSH_CMSG_EOF alone does not
|
||||
* always appear to be enough. So we
|
||||
* try to send an EOF character first.
|
||||
*/
|
||||
packet_start(SSH_CMSG_STDIN_DATA);
|
||||
packet_put_string("\004", 1);
|
||||
packet_send();
|
||||
/* Close stdin. */
|
||||
stdin_eof = 1;
|
||||
if (buffer_len(bin) == 0) {
|
||||
packet_start(SSH_CMSG_EOF);
|
||||
packet_send();
|
||||
}
|
||||
}
|
||||
continue;
|
||||
|
||||
buffer_append(bin, "\004", 1);
|
||||
/* fake EOF on stdin */
|
||||
return -1;
|
||||
case '?':
|
||||
print_escape_help(berr, escape_char, compat20,
|
||||
print_escape_help(berr, escape_char,
|
||||
(c && c->ctl_chan != -1),
|
||||
log_is_on_stderr());
|
||||
continue;
|
||||
@ -1325,115 +1166,6 @@ process_escapes(Channel *c, Buffer *bin, Buffer *bout, Buffer *berr,
|
||||
return bytes;
|
||||
}
|
||||
|
||||
static void
|
||||
client_process_input(fd_set *readset)
|
||||
{
|
||||
int len;
|
||||
char buf[SSH_IOBUFSZ];
|
||||
|
||||
/* Read input from stdin. */
|
||||
if (FD_ISSET(fileno(stdin), readset)) {
|
||||
/* Read as much as possible. */
|
||||
len = read(fileno(stdin), buf, sizeof(buf));
|
||||
if (len < 0 &&
|
||||
(errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK))
|
||||
return; /* we'll try again later */
|
||||
if (len <= 0) {
|
||||
/*
|
||||
* Received EOF or error. They are treated
|
||||
* similarly, except that an error message is printed
|
||||
* if it was an error condition.
|
||||
*/
|
||||
if (len < 0) {
|
||||
snprintf(buf, sizeof buf, "read: %.100s\r\n",
|
||||
strerror(errno));
|
||||
buffer_append(&stderr_buffer, buf, strlen(buf));
|
||||
}
|
||||
/* Mark that we have seen EOF. */
|
||||
stdin_eof = 1;
|
||||
/*
|
||||
* Send an EOF message to the server unless there is
|
||||
* data in the buffer. If there is data in the
|
||||
* buffer, no message will be sent now. Code
|
||||
* elsewhere will send the EOF when the buffer
|
||||
* becomes empty if stdin_eof is set.
|
||||
*/
|
||||
if (buffer_len(&stdin_buffer) == 0) {
|
||||
packet_start(SSH_CMSG_EOF);
|
||||
packet_send();
|
||||
}
|
||||
} else if (escape_char1 == SSH_ESCAPECHAR_NONE) {
|
||||
/*
|
||||
* Normal successful read, and no escape character.
|
||||
* Just append the data to buffer.
|
||||
*/
|
||||
buffer_append(&stdin_buffer, buf, len);
|
||||
} else {
|
||||
/*
|
||||
* Normal, successful read. But we have an escape
|
||||
* character and have to process the characters one
|
||||
* by one.
|
||||
*/
|
||||
if (process_escapes(NULL, &stdin_buffer,
|
||||
&stdout_buffer, &stderr_buffer, buf, len) == -1)
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
client_process_output(fd_set *writeset)
|
||||
{
|
||||
int len;
|
||||
char buf[100];
|
||||
|
||||
/* Write buffered output to stdout. */
|
||||
if (FD_ISSET(fileno(stdout), writeset)) {
|
||||
/* Write as much data as possible. */
|
||||
len = write(fileno(stdout), buffer_ptr(&stdout_buffer),
|
||||
buffer_len(&stdout_buffer));
|
||||
if (len <= 0) {
|
||||
if (errno == EINTR || errno == EAGAIN ||
|
||||
errno == EWOULDBLOCK)
|
||||
len = 0;
|
||||
else {
|
||||
/*
|
||||
* An error or EOF was encountered. Put an
|
||||
* error message to stderr buffer.
|
||||
*/
|
||||
snprintf(buf, sizeof buf,
|
||||
"write stdout: %.50s\r\n", strerror(errno));
|
||||
buffer_append(&stderr_buffer, buf, strlen(buf));
|
||||
quit_pending = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* Consume printed data from the buffer. */
|
||||
buffer_consume(&stdout_buffer, len);
|
||||
}
|
||||
/* Write buffered output to stderr. */
|
||||
if (FD_ISSET(fileno(stderr), writeset)) {
|
||||
/* Write as much data as possible. */
|
||||
len = write(fileno(stderr), buffer_ptr(&stderr_buffer),
|
||||
buffer_len(&stderr_buffer));
|
||||
if (len <= 0) {
|
||||
if (errno == EINTR || errno == EAGAIN ||
|
||||
errno == EWOULDBLOCK)
|
||||
len = 0;
|
||||
else {
|
||||
/*
|
||||
* EOF or error, but can't even print
|
||||
* error message.
|
||||
*/
|
||||
quit_pending = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* Consume printed characters from the buffer. */
|
||||
buffer_consume(&stderr_buffer, len);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Get packets from the connection input buffer, and process them as long as
|
||||
* there are packets available.
|
||||
@ -1553,18 +1285,6 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
|
||||
connection_out = packet_get_connection_out();
|
||||
max_fd = MAXIMUM(connection_in, connection_out);
|
||||
|
||||
if (!compat20) {
|
||||
/* enable nonblocking unless tty */
|
||||
if (!isatty(fileno(stdin)))
|
||||
set_nonblock(fileno(stdin));
|
||||
if (!isatty(fileno(stdout)))
|
||||
set_nonblock(fileno(stdout));
|
||||
if (!isatty(fileno(stderr)))
|
||||
set_nonblock(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;
|
||||
|
||||
@ -1592,22 +1312,17 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
|
||||
if (have_pty)
|
||||
enter_raw_mode(options.request_tty == REQUEST_TTY_FORCE);
|
||||
|
||||
if (compat20) {
|
||||
session_ident = ssh2_chan_id;
|
||||
if (session_ident != -1) {
|
||||
if (escape_char_arg != SSH_ESCAPECHAR_NONE) {
|
||||
channel_register_filter(session_ident,
|
||||
client_simple_escape_filter, NULL,
|
||||
client_filter_cleanup,
|
||||
client_new_escape_filter_ctx(
|
||||
escape_char_arg));
|
||||
}
|
||||
channel_register_cleanup(session_ident,
|
||||
client_channel_closed, 0);
|
||||
session_ident = ssh2_chan_id;
|
||||
if (session_ident != -1) {
|
||||
if (escape_char_arg != SSH_ESCAPECHAR_NONE) {
|
||||
channel_register_filter(session_ident,
|
||||
client_simple_escape_filter, NULL,
|
||||
client_filter_cleanup,
|
||||
client_new_escape_filter_ctx(
|
||||
escape_char_arg));
|
||||
}
|
||||
} else {
|
||||
/* Check if we should immediately send eof on stdin. */
|
||||
client_check_initial_eof_on_stdin();
|
||||
channel_register_cleanup(session_ident,
|
||||
client_channel_closed, 0);
|
||||
}
|
||||
|
||||
/* Main loop of the client for the interactive session mode. */
|
||||
@ -1616,7 +1331,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
|
||||
/* Process buffered packets sent by the server. */
|
||||
client_process_buffered_input_packets();
|
||||
|
||||
if (compat20 && session_closed && !channel_still_open())
|
||||
if (session_closed && !channel_still_open())
|
||||
break;
|
||||
|
||||
if (ssh_packet_is_rekeying(active_state)) {
|
||||
@ -1629,13 +1344,6 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
|
||||
ssh_err(r));
|
||||
need_rekeying = 0;
|
||||
} else {
|
||||
/*
|
||||
* Make packets of buffered stdin data, and buffer
|
||||
* them for sending to the server.
|
||||
*/
|
||||
if (!compat20)
|
||||
client_make_packets_from_stdin_data();
|
||||
|
||||
/*
|
||||
* Make packets from buffered channel data, and
|
||||
* enqueue them for sending to the server.
|
||||
@ -1673,16 +1381,6 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
|
||||
if (quit_pending)
|
||||
break;
|
||||
|
||||
if (!compat20) {
|
||||
/* Buffer data from stdin */
|
||||
client_process_input(readset);
|
||||
/*
|
||||
* Process output to stdout and stderr. Output to
|
||||
* the connection is processed elsewhere (above).
|
||||
*/
|
||||
client_process_output(writeset);
|
||||
}
|
||||
|
||||
/*
|
||||
* Send as much buffered packet data as possible to the
|
||||
* sender.
|
||||
@ -1710,14 +1408,12 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
|
||||
/* Stop watching for window change. */
|
||||
signal(SIGWINCH, SIG_DFL);
|
||||
|
||||
if (compat20) {
|
||||
packet_start(SSH2_MSG_DISCONNECT);
|
||||
packet_put_int(SSH2_DISCONNECT_BY_APPLICATION);
|
||||
packet_put_cstring("disconnected by user");
|
||||
packet_put_cstring(""); /* language tag */
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
}
|
||||
packet_start(SSH2_MSG_DISCONNECT);
|
||||
packet_put_int(SSH2_DISCONNECT_BY_APPLICATION);
|
||||
packet_put_cstring("disconnected by user");
|
||||
packet_put_cstring(""); /* language tag */
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
|
||||
channel_free_all();
|
||||
|
||||
@ -1796,92 +1492,6 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
|
||||
|
||||
/*********/
|
||||
|
||||
static int
|
||||
client_input_stdout_data(int type, u_int32_t seq, void *ctxt)
|
||||
{
|
||||
u_int data_len;
|
||||
char *data = packet_get_string(&data_len);
|
||||
packet_check_eom();
|
||||
buffer_append(&stdout_buffer, data, data_len);
|
||||
explicit_bzero(data, data_len);
|
||||
free(data);
|
||||
return 0;
|
||||
}
|
||||
static int
|
||||
client_input_stderr_data(int type, u_int32_t seq, void *ctxt)
|
||||
{
|
||||
u_int data_len;
|
||||
char *data = packet_get_string(&data_len);
|
||||
packet_check_eom();
|
||||
buffer_append(&stderr_buffer, data, data_len);
|
||||
explicit_bzero(data, data_len);
|
||||
free(data);
|
||||
return 0;
|
||||
}
|
||||
static int
|
||||
client_input_exit_status(int type, u_int32_t seq, void *ctxt)
|
||||
{
|
||||
exit_status = packet_get_int();
|
||||
packet_check_eom();
|
||||
/* Acknowledge the exit. */
|
||||
packet_start(SSH_CMSG_EXIT_CONFIRMATION);
|
||||
packet_send();
|
||||
/*
|
||||
* Must wait for packet to be sent since we are
|
||||
* exiting the loop.
|
||||
*/
|
||||
packet_write_wait();
|
||||
/* Flag that we want to exit. */
|
||||
quit_pending = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
client_input_agent_open(int type, u_int32_t seq, void *ctxt)
|
||||
{
|
||||
Channel *c = NULL;
|
||||
int r, remote_id, sock;
|
||||
|
||||
/* Read the remote channel number from the message. */
|
||||
remote_id = packet_get_int();
|
||||
packet_check_eom();
|
||||
|
||||
/*
|
||||
* Get a connection to the local authentication agent (this may again
|
||||
* get forwarded).
|
||||
*/
|
||||
if ((r = ssh_get_authentication_socket(&sock)) != 0 &&
|
||||
r != SSH_ERR_AGENT_NOT_PRESENT)
|
||||
debug("%s: ssh_get_authentication_socket: %s",
|
||||
__func__, ssh_err(r));
|
||||
|
||||
|
||||
/*
|
||||
* If we could not connect the agent, send an error message back to
|
||||
* the server. This should never happen unless the agent dies,
|
||||
* because authentication forwarding is only enabled if we have an
|
||||
* agent.
|
||||
*/
|
||||
if (sock >= 0) {
|
||||
c = channel_new("", SSH_CHANNEL_OPEN, sock, sock,
|
||||
-1, 0, 0, 0, "authentication agent connection", 1);
|
||||
c->remote_id = remote_id;
|
||||
c->force_drain = 1;
|
||||
}
|
||||
if (c == NULL) {
|
||||
packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
|
||||
packet_put_int(remote_id);
|
||||
} else {
|
||||
/* Send a confirmation to the remote host. */
|
||||
debug("Forwarding authentication connection.");
|
||||
packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION);
|
||||
packet_put_int(remote_id);
|
||||
packet_put_int(c->self);
|
||||
}
|
||||
packet_send();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Channel *
|
||||
client_request_forwarded_tcpip(const char *request_type, int rchan,
|
||||
u_int rwindow, u_int rmaxpack)
|
||||
@ -2032,11 +1642,6 @@ client_request_tun_fwd(int tun_mode, int local_tun, int remote_tun)
|
||||
if (tun_mode == SSH_TUNMODE_NO)
|
||||
return 0;
|
||||
|
||||
if (!compat20) {
|
||||
error("Tunnel forwarding is not supported for protocol 1");
|
||||
return -1;
|
||||
}
|
||||
|
||||
debug("Requesting tun unit %d in mode %d", local_tun, tun_mode);
|
||||
|
||||
/* Open local tunnel device */
|
||||
@ -2687,7 +2292,7 @@ client_session2_setup(int id, int want_tty, int want_subsystem,
|
||||
}
|
||||
|
||||
static void
|
||||
client_init_dispatch_20(void)
|
||||
client_init_dispatch(void)
|
||||
{
|
||||
dispatch_init(&dispatch_protocol_error);
|
||||
|
||||
@ -2712,45 +2317,6 @@ client_init_dispatch_20(void)
|
||||
dispatch_set(SSH2_MSG_REQUEST_SUCCESS, &client_global_request_reply);
|
||||
}
|
||||
|
||||
static void
|
||||
client_init_dispatch_13(void)
|
||||
{
|
||||
dispatch_init(NULL);
|
||||
dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_close);
|
||||
dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, &channel_input_close_confirmation);
|
||||
dispatch_set(SSH_MSG_CHANNEL_DATA, &channel_input_data);
|
||||
dispatch_set(SSH_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation);
|
||||
dispatch_set(SSH_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure);
|
||||
dispatch_set(SSH_MSG_PORT_OPEN, &channel_input_port_open);
|
||||
dispatch_set(SSH_SMSG_EXITSTATUS, &client_input_exit_status);
|
||||
dispatch_set(SSH_SMSG_STDERR_DATA, &client_input_stderr_data);
|
||||
dispatch_set(SSH_SMSG_STDOUT_DATA, &client_input_stdout_data);
|
||||
|
||||
dispatch_set(SSH_SMSG_AGENT_OPEN, options.forward_agent ?
|
||||
&client_input_agent_open : &deny_input_open);
|
||||
dispatch_set(SSH_SMSG_X11_OPEN, options.forward_x11 ?
|
||||
&x11_input_open : &deny_input_open);
|
||||
}
|
||||
|
||||
static void
|
||||
client_init_dispatch_15(void)
|
||||
{
|
||||
client_init_dispatch_13();
|
||||
dispatch_set(SSH_MSG_CHANNEL_CLOSE, &channel_input_ieof);
|
||||
dispatch_set(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION, & channel_input_oclose);
|
||||
}
|
||||
|
||||
static void
|
||||
client_init_dispatch(void)
|
||||
{
|
||||
if (compat20)
|
||||
client_init_dispatch_20();
|
||||
else if (compat13)
|
||||
client_init_dispatch_13();
|
||||
else
|
||||
client_init_dispatch_15();
|
||||
}
|
||||
|
||||
void
|
||||
client_stop_mux(void)
|
||||
{
|
||||
|
18
compat.c
18
compat.c
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: compat.c,v 1.102 2017/04/30 23:11:45 djm Exp $ */
|
||||
/* $OpenBSD: compat.c,v 1.103 2017/04/30 23:13:25 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl. All rights reserved.
|
||||
*
|
||||
@ -39,24 +39,8 @@
|
||||
#include "match.h"
|
||||
#include "kex.h"
|
||||
|
||||
int compat13 = 0;
|
||||
int compat20 = 0;
|
||||
int datafellows = 0;
|
||||
|
||||
void
|
||||
enable_compat20(void)
|
||||
{
|
||||
if (compat20)
|
||||
return;
|
||||
debug("Enabling compatibility mode for protocol 2.0");
|
||||
compat20 = 1;
|
||||
}
|
||||
void
|
||||
enable_compat13(void)
|
||||
{
|
||||
debug("Enabling compatibility mode for protocol 1.3");
|
||||
compat13 = 1;
|
||||
}
|
||||
/* datafellows bug compatibility */
|
||||
u_int
|
||||
compat_datafellows(const char *version)
|
||||
|
6
compat.h
6
compat.h
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: compat.h,v 1.48 2015/05/26 23:23:40 dtucker Exp $ */
|
||||
/* $OpenBSD: compat.h,v 1.49 2017/04/30 23:13:25 djm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1999, 2000, 2001 Markus Friedl. All rights reserved.
|
||||
@ -63,15 +63,11 @@
|
||||
#define SSH_BUG_HOSTKEYS 0x20000000
|
||||
#define SSH_BUG_DHGEX_LARGE 0x40000000
|
||||
|
||||
void enable_compat13(void);
|
||||
void enable_compat20(void);
|
||||
u_int compat_datafellows(const char *);
|
||||
int proto_spec(const char *);
|
||||
char *compat_cipher_proposal(char *);
|
||||
char *compat_pkalg_proposal(char *);
|
||||
char *compat_kex_proposal(char *);
|
||||
|
||||
extern int compat13;
|
||||
extern int compat20;
|
||||
extern int datafellows;
|
||||
#endif
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: dispatch.c,v 1.27 2015/05/01 07:10:01 djm Exp $ */
|
||||
/* $OpenBSD: dispatch.c,v 1.28 2017/04/30 23:13:25 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2000 Markus Friedl. All rights reserved.
|
||||
*
|
||||
@ -45,8 +45,6 @@ dispatch_protocol_error(int type, u_int32_t seq, void *ctx)
|
||||
int r;
|
||||
|
||||
logit("dispatch_protocol_error: type %d seq %u", type, seq);
|
||||
if (!compat20)
|
||||
fatal("protocol error");
|
||||
if ((r = sshpkt_start(ssh, SSH2_MSG_UNIMPLEMENTED)) != 0 ||
|
||||
(r = sshpkt_put_u32(ssh, seq)) != 0 ||
|
||||
(r = sshpkt_send(ssh)) != 0 ||
|
||||
|
308
nchan.c
308
nchan.c
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: nchan.c,v 1.63 2010/01/26 01:28:35 djm Exp $ */
|
||||
/* $OpenBSD: nchan.c,v 1.64 2017/04/30 23:13:25 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl. All rights reserved.
|
||||
*
|
||||
@ -74,9 +74,6 @@
|
||||
/*
|
||||
* ACTIONS: should never update the channel states
|
||||
*/
|
||||
static void chan_send_ieof1(Channel *);
|
||||
static void chan_send_oclose1(Channel *);
|
||||
static void chan_send_close2(Channel *);
|
||||
static void chan_send_eof2(Channel *);
|
||||
static void chan_send_eow2(Channel *);
|
||||
|
||||
@ -96,6 +93,7 @@ chan_set_istate(Channel *c, u_int next)
|
||||
istates[next]);
|
||||
c->istate = next;
|
||||
}
|
||||
|
||||
static void
|
||||
chan_set_ostate(Channel *c, u_int next)
|
||||
{
|
||||
@ -106,34 +104,6 @@ chan_set_ostate(Channel *c, u_int next)
|
||||
c->ostate = next;
|
||||
}
|
||||
|
||||
/*
|
||||
* SSH1 specific implementation of event functions
|
||||
*/
|
||||
|
||||
static void
|
||||
chan_rcvd_oclose1(Channel *c)
|
||||
{
|
||||
debug2("channel %d: rcvd oclose", c->self);
|
||||
switch (c->istate) {
|
||||
case CHAN_INPUT_WAIT_OCLOSE:
|
||||
chan_set_istate(c, CHAN_INPUT_CLOSED);
|
||||
break;
|
||||
case CHAN_INPUT_OPEN:
|
||||
chan_shutdown_read(c);
|
||||
chan_send_ieof1(c);
|
||||
chan_set_istate(c, CHAN_INPUT_CLOSED);
|
||||
break;
|
||||
case CHAN_INPUT_WAIT_DRAIN:
|
||||
/* both local read_failed and remote write_failed */
|
||||
chan_send_ieof1(c);
|
||||
chan_set_istate(c, CHAN_INPUT_CLOSED);
|
||||
break;
|
||||
default:
|
||||
error("channel %d: protocol error: rcvd_oclose for istate %d",
|
||||
c->self, c->istate);
|
||||
return;
|
||||
}
|
||||
}
|
||||
void
|
||||
chan_read_failed(Channel *c)
|
||||
{
|
||||
@ -149,6 +119,7 @@ chan_read_failed(Channel *c)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
chan_ibuf_empty(Channel *c)
|
||||
{
|
||||
@ -160,14 +131,9 @@ chan_ibuf_empty(Channel *c)
|
||||
}
|
||||
switch (c->istate) {
|
||||
case CHAN_INPUT_WAIT_DRAIN:
|
||||
if (compat20) {
|
||||
if (!(c->flags & (CHAN_CLOSE_SENT|CHAN_LOCAL)))
|
||||
chan_send_eof2(c);
|
||||
chan_set_istate(c, CHAN_INPUT_CLOSED);
|
||||
} else {
|
||||
chan_send_ieof1(c);
|
||||
chan_set_istate(c, CHAN_INPUT_WAIT_OCLOSE);
|
||||
}
|
||||
if (!(c->flags & (CHAN_CLOSE_SENT|CHAN_LOCAL)))
|
||||
chan_send_eof2(c);
|
||||
chan_set_istate(c, CHAN_INPUT_CLOSED);
|
||||
break;
|
||||
default:
|
||||
error("channel %d: chan_ibuf_empty for istate %d",
|
||||
@ -175,44 +141,7 @@ chan_ibuf_empty(Channel *c)
|
||||
break;
|
||||
}
|
||||
}
|
||||
static void
|
||||
chan_rcvd_ieof1(Channel *c)
|
||||
{
|
||||
debug2("channel %d: rcvd ieof", c->self);
|
||||
switch (c->ostate) {
|
||||
case CHAN_OUTPUT_OPEN:
|
||||
chan_set_ostate(c, CHAN_OUTPUT_WAIT_DRAIN);
|
||||
break;
|
||||
case CHAN_OUTPUT_WAIT_IEOF:
|
||||
chan_set_ostate(c, CHAN_OUTPUT_CLOSED);
|
||||
break;
|
||||
default:
|
||||
error("channel %d: protocol error: rcvd_ieof for ostate %d",
|
||||
c->self, c->ostate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
static void
|
||||
chan_write_failed1(Channel *c)
|
||||
{
|
||||
debug2("channel %d: write failed", c->self);
|
||||
switch (c->ostate) {
|
||||
case CHAN_OUTPUT_OPEN:
|
||||
chan_shutdown_write(c);
|
||||
chan_send_oclose1(c);
|
||||
chan_set_ostate(c, CHAN_OUTPUT_WAIT_IEOF);
|
||||
break;
|
||||
case CHAN_OUTPUT_WAIT_DRAIN:
|
||||
chan_shutdown_write(c);
|
||||
chan_send_oclose1(c);
|
||||
chan_set_ostate(c, CHAN_OUTPUT_CLOSED);
|
||||
break;
|
||||
default:
|
||||
error("channel %d: chan_write_failed for ostate %d",
|
||||
c->self, c->ostate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
chan_obuf_empty(Channel *c)
|
||||
{
|
||||
@ -225,8 +154,6 @@ chan_obuf_empty(Channel *c)
|
||||
switch (c->ostate) {
|
||||
case CHAN_OUTPUT_WAIT_DRAIN:
|
||||
chan_shutdown_write(c);
|
||||
if (!compat20)
|
||||
chan_send_oclose1(c);
|
||||
chan_set_ostate(c, CHAN_OUTPUT_CLOSED);
|
||||
break;
|
||||
default:
|
||||
@ -235,47 +162,90 @@ chan_obuf_empty(Channel *c)
|
||||
break;
|
||||
}
|
||||
}
|
||||
static void
|
||||
chan_send_ieof1(Channel *c)
|
||||
|
||||
void
|
||||
chan_rcvd_eow(Channel *c)
|
||||
{
|
||||
debug2("channel %d: send ieof", c->self);
|
||||
debug2("channel %d: rcvd eow", c->self);
|
||||
switch (c->istate) {
|
||||
case CHAN_INPUT_OPEN:
|
||||
case CHAN_INPUT_WAIT_DRAIN:
|
||||
packet_start(SSH_MSG_CHANNEL_INPUT_EOF);
|
||||
packet_put_int(c->remote_id);
|
||||
packet_send();
|
||||
break;
|
||||
default:
|
||||
error("channel %d: cannot send ieof for istate %d",
|
||||
c->self, c->istate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
static void
|
||||
chan_send_oclose1(Channel *c)
|
||||
{
|
||||
debug2("channel %d: send oclose", c->self);
|
||||
switch (c->ostate) {
|
||||
case CHAN_OUTPUT_OPEN:
|
||||
case CHAN_OUTPUT_WAIT_DRAIN:
|
||||
buffer_clear(&c->output);
|
||||
packet_start(SSH_MSG_CHANNEL_OUTPUT_CLOSE);
|
||||
packet_put_int(c->remote_id);
|
||||
packet_send();
|
||||
break;
|
||||
default:
|
||||
error("channel %d: cannot send oclose for ostate %d",
|
||||
c->self, c->ostate);
|
||||
chan_shutdown_read(c);
|
||||
chan_set_istate(c, CHAN_INPUT_CLOSED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* the same for SSH2
|
||||
*/
|
||||
static void
|
||||
chan_rcvd_close2(Channel *c)
|
||||
chan_send_eof2(Channel *c)
|
||||
{
|
||||
debug2("channel %d: send eof", c->self);
|
||||
switch (c->istate) {
|
||||
case CHAN_INPUT_WAIT_DRAIN:
|
||||
packet_start(SSH2_MSG_CHANNEL_EOF);
|
||||
packet_put_int(c->remote_id);
|
||||
packet_send();
|
||||
c->flags |= CHAN_EOF_SENT;
|
||||
break;
|
||||
default:
|
||||
error("channel %d: cannot send eof for istate %d",
|
||||
c->self, c->istate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
chan_send_close2(Channel *c)
|
||||
{
|
||||
debug2("channel %d: send close", c->self);
|
||||
if (c->ostate != CHAN_OUTPUT_CLOSED ||
|
||||
c->istate != CHAN_INPUT_CLOSED) {
|
||||
error("channel %d: cannot send close for istate/ostate %d/%d",
|
||||
c->self, c->istate, c->ostate);
|
||||
} else if (c->flags & CHAN_CLOSE_SENT) {
|
||||
error("channel %d: already sent close", c->self);
|
||||
} else {
|
||||
packet_start(SSH2_MSG_CHANNEL_CLOSE);
|
||||
packet_put_int(c->remote_id);
|
||||
packet_send();
|
||||
c->flags |= CHAN_CLOSE_SENT;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
chan_send_eow2(Channel *c)
|
||||
{
|
||||
debug2("channel %d: send eow", c->self);
|
||||
if (c->ostate == CHAN_OUTPUT_CLOSED) {
|
||||
error("channel %d: must not sent eow on closed output",
|
||||
c->self);
|
||||
return;
|
||||
}
|
||||
if (!(datafellows & SSH_NEW_OPENSSH))
|
||||
return;
|
||||
packet_start(SSH2_MSG_CHANNEL_REQUEST);
|
||||
packet_put_int(c->remote_id);
|
||||
packet_put_cstring("eow@openssh.com");
|
||||
packet_put_char(0);
|
||||
packet_send();
|
||||
}
|
||||
|
||||
/* shared */
|
||||
|
||||
void
|
||||
chan_rcvd_ieof(Channel *c)
|
||||
{
|
||||
debug2("channel %d: rcvd eof", c->self);
|
||||
c->flags |= CHAN_EOF_RCVD;
|
||||
if (c->ostate == CHAN_OUTPUT_OPEN)
|
||||
chan_set_ostate(c, CHAN_OUTPUT_WAIT_DRAIN);
|
||||
if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN &&
|
||||
buffer_len(&c->output) == 0 &&
|
||||
!CHANNEL_EFD_OUTPUT_ACTIVE(c))
|
||||
chan_obuf_empty(c);
|
||||
}
|
||||
|
||||
void
|
||||
chan_rcvd_oclose(Channel *c)
|
||||
{
|
||||
debug2("channel %d: rcvd close", c->self);
|
||||
if (!(c->flags & CHAN_LOCAL)) {
|
||||
@ -313,26 +283,7 @@ chan_rcvd_close2(Channel *c)
|
||||
}
|
||||
|
||||
void
|
||||
chan_rcvd_eow(Channel *c)
|
||||
{
|
||||
debug2("channel %d: rcvd eow", c->self);
|
||||
switch (c->istate) {
|
||||
case CHAN_INPUT_OPEN:
|
||||
chan_shutdown_read(c);
|
||||
chan_set_istate(c, CHAN_INPUT_CLOSED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
static void
|
||||
chan_rcvd_eof2(Channel *c)
|
||||
{
|
||||
debug2("channel %d: rcvd eof", c->self);
|
||||
c->flags |= CHAN_EOF_RCVD;
|
||||
if (c->ostate == CHAN_OUTPUT_OPEN)
|
||||
chan_set_ostate(c, CHAN_OUTPUT_WAIT_DRAIN);
|
||||
}
|
||||
static void
|
||||
chan_write_failed2(Channel *c)
|
||||
chan_write_failed(Channel *c)
|
||||
{
|
||||
debug2("channel %d: write failed", c->self);
|
||||
switch (c->ostate) {
|
||||
@ -349,88 +300,6 @@ chan_write_failed2(Channel *c)
|
||||
break;
|
||||
}
|
||||
}
|
||||
static void
|
||||
chan_send_eof2(Channel *c)
|
||||
{
|
||||
debug2("channel %d: send eof", c->self);
|
||||
switch (c->istate) {
|
||||
case CHAN_INPUT_WAIT_DRAIN:
|
||||
packet_start(SSH2_MSG_CHANNEL_EOF);
|
||||
packet_put_int(c->remote_id);
|
||||
packet_send();
|
||||
c->flags |= CHAN_EOF_SENT;
|
||||
break;
|
||||
default:
|
||||
error("channel %d: cannot send eof for istate %d",
|
||||
c->self, c->istate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
static void
|
||||
chan_send_close2(Channel *c)
|
||||
{
|
||||
debug2("channel %d: send close", c->self);
|
||||
if (c->ostate != CHAN_OUTPUT_CLOSED ||
|
||||
c->istate != CHAN_INPUT_CLOSED) {
|
||||
error("channel %d: cannot send close for istate/ostate %d/%d",
|
||||
c->self, c->istate, c->ostate);
|
||||
} else if (c->flags & CHAN_CLOSE_SENT) {
|
||||
error("channel %d: already sent close", c->self);
|
||||
} else {
|
||||
packet_start(SSH2_MSG_CHANNEL_CLOSE);
|
||||
packet_put_int(c->remote_id);
|
||||
packet_send();
|
||||
c->flags |= CHAN_CLOSE_SENT;
|
||||
}
|
||||
}
|
||||
static void
|
||||
chan_send_eow2(Channel *c)
|
||||
{
|
||||
debug2("channel %d: send eow", c->self);
|
||||
if (c->ostate == CHAN_OUTPUT_CLOSED) {
|
||||
error("channel %d: must not sent eow on closed output",
|
||||
c->self);
|
||||
return;
|
||||
}
|
||||
if (!(datafellows & SSH_NEW_OPENSSH))
|
||||
return;
|
||||
packet_start(SSH2_MSG_CHANNEL_REQUEST);
|
||||
packet_put_int(c->remote_id);
|
||||
packet_put_cstring("eow@openssh.com");
|
||||
packet_put_char(0);
|
||||
packet_send();
|
||||
}
|
||||
|
||||
/* shared */
|
||||
|
||||
void
|
||||
chan_rcvd_ieof(Channel *c)
|
||||
{
|
||||
if (compat20)
|
||||
chan_rcvd_eof2(c);
|
||||
else
|
||||
chan_rcvd_ieof1(c);
|
||||
if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN &&
|
||||
buffer_len(&c->output) == 0 &&
|
||||
!CHANNEL_EFD_OUTPUT_ACTIVE(c))
|
||||
chan_obuf_empty(c);
|
||||
}
|
||||
void
|
||||
chan_rcvd_oclose(Channel *c)
|
||||
{
|
||||
if (compat20)
|
||||
chan_rcvd_close2(c);
|
||||
else
|
||||
chan_rcvd_oclose1(c);
|
||||
}
|
||||
void
|
||||
chan_write_failed(Channel *c)
|
||||
{
|
||||
if (compat20)
|
||||
chan_write_failed2(c);
|
||||
else
|
||||
chan_write_failed1(c);
|
||||
}
|
||||
|
||||
void
|
||||
chan_mark_dead(Channel *c)
|
||||
@ -447,10 +316,6 @@ chan_is_dead(Channel *c, int do_send)
|
||||
}
|
||||
if (c->istate != CHAN_INPUT_CLOSED || c->ostate != CHAN_OUTPUT_CLOSED)
|
||||
return 0;
|
||||
if (!compat20) {
|
||||
debug2("channel %d: is dead", c->self);
|
||||
return 1;
|
||||
}
|
||||
if ((datafellows & SSH_BUG_EXTEOF) &&
|
||||
c->extended_usage == CHAN_EXTENDED_WRITE &&
|
||||
c->efd != -1 &&
|
||||
@ -488,7 +353,7 @@ static void
|
||||
chan_shutdown_write(Channel *c)
|
||||
{
|
||||
buffer_clear(&c->output);
|
||||
if (compat20 && c->type == SSH_CHANNEL_LARVAL)
|
||||
if (c->type == SSH_CHANNEL_LARVAL)
|
||||
return;
|
||||
/* shutdown failure is allowed if write failed already */
|
||||
debug2("channel %d: close_write", c->self);
|
||||
@ -504,10 +369,11 @@ chan_shutdown_write(Channel *c)
|
||||
c->self, c->wfd, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
chan_shutdown_read(Channel *c)
|
||||
{
|
||||
if (compat20 && c->type == SSH_CHANNEL_LARVAL)
|
||||
if (c->type == SSH_CHANNEL_LARVAL)
|
||||
return;
|
||||
debug2("channel %d: close_read", c->self);
|
||||
if (c->sock != -1) {
|
||||
|
391
packet.c
391
packet.c
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: packet.c,v 1.248 2017/04/30 23:10:43 djm Exp $ */
|
||||
/* $OpenBSD: packet.c,v 1.249 2017/04/30 23:13:25 djm Exp $ */
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
@ -278,8 +278,8 @@ ssh_packet_set_input_hook(struct ssh *ssh, ssh_packet_hook_fn *hook, void *ctx)
|
||||
int
|
||||
ssh_packet_is_rekeying(struct ssh *ssh)
|
||||
{
|
||||
return compat20 &&
|
||||
(ssh->state->rekeying || (ssh->kex != NULL && ssh->kex->done == 0));
|
||||
return ssh->state->rekeying ||
|
||||
(ssh->kex != NULL && ssh->kex->done == 0);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -698,7 +698,7 @@ ssh_packet_start_compression(struct ssh *ssh, int level)
|
||||
{
|
||||
int r;
|
||||
|
||||
if (ssh->state->packet_compression && !compat20)
|
||||
if (ssh->state->packet_compression)
|
||||
return SSH_ERR_INTERNAL_ERROR;
|
||||
ssh->state->packet_compression = 1;
|
||||
if ((r = ssh_packet_init_compression(ssh)) != 0 ||
|
||||
@ -814,99 +814,6 @@ ssh_packet_set_encryption_key(struct ssh *ssh, const u_char *key, u_int keylen,
|
||||
fatal("no SSH protocol 1 support");
|
||||
}
|
||||
|
||||
/*
|
||||
* Finalizes and sends the packet. If the encryption key has been set,
|
||||
* encrypts the packet before sending.
|
||||
*/
|
||||
|
||||
int
|
||||
ssh_packet_send1(struct ssh *ssh)
|
||||
{
|
||||
struct session_state *state = ssh->state;
|
||||
u_char buf[8], *cp;
|
||||
int r, padding, len;
|
||||
u_int checksum;
|
||||
|
||||
/*
|
||||
* If using packet compression, compress the payload of the outgoing
|
||||
* packet.
|
||||
*/
|
||||
if (state->packet_compression) {
|
||||
sshbuf_reset(state->compression_buffer);
|
||||
/* Skip padding. */
|
||||
if ((r = sshbuf_consume(state->outgoing_packet, 8)) != 0)
|
||||
goto out;
|
||||
/* padding */
|
||||
if ((r = sshbuf_put(state->compression_buffer,
|
||||
"\0\0\0\0\0\0\0\0", 8)) != 0)
|
||||
goto out;
|
||||
if ((r = compress_buffer(ssh, state->outgoing_packet,
|
||||
state->compression_buffer)) != 0)
|
||||
goto out;
|
||||
sshbuf_reset(state->outgoing_packet);
|
||||
if ((r = sshbuf_putb(state->outgoing_packet,
|
||||
state->compression_buffer)) != 0)
|
||||
goto out;
|
||||
}
|
||||
/* Compute packet length without padding (add checksum, remove padding). */
|
||||
len = sshbuf_len(state->outgoing_packet) + 4 - 8;
|
||||
|
||||
/* Insert padding. Initialized to zero in packet_start1() */
|
||||
padding = 8 - len % 8;
|
||||
if (!cipher_ctx_is_plaintext(state->send_context)) {
|
||||
cp = sshbuf_mutable_ptr(state->outgoing_packet);
|
||||
if (cp == NULL) {
|
||||
r = SSH_ERR_INTERNAL_ERROR;
|
||||
goto out;
|
||||
}
|
||||
arc4random_buf(cp + 8 - padding, padding);
|
||||
}
|
||||
if ((r = sshbuf_consume(state->outgoing_packet, 8 - padding)) != 0)
|
||||
goto out;
|
||||
|
||||
/* Add check bytes. */
|
||||
checksum = ssh_crc32(sshbuf_ptr(state->outgoing_packet),
|
||||
sshbuf_len(state->outgoing_packet));
|
||||
POKE_U32(buf, checksum);
|
||||
if ((r = sshbuf_put(state->outgoing_packet, buf, 4)) != 0)
|
||||
goto out;
|
||||
|
||||
#ifdef PACKET_DEBUG
|
||||
fprintf(stderr, "packet_send plain: ");
|
||||
sshbuf_dump(state->outgoing_packet, stderr);
|
||||
#endif
|
||||
|
||||
/* Append to output. */
|
||||
POKE_U32(buf, len);
|
||||
if ((r = sshbuf_put(state->output, buf, 4)) != 0)
|
||||
goto out;
|
||||
if ((r = sshbuf_reserve(state->output,
|
||||
sshbuf_len(state->outgoing_packet), &cp)) != 0)
|
||||
goto out;
|
||||
if ((r = cipher_crypt(state->send_context, 0, cp,
|
||||
sshbuf_ptr(state->outgoing_packet),
|
||||
sshbuf_len(state->outgoing_packet), 0, 0)) != 0)
|
||||
goto out;
|
||||
|
||||
#ifdef PACKET_DEBUG
|
||||
fprintf(stderr, "encrypted: ");
|
||||
sshbuf_dump(state->output, stderr);
|
||||
#endif
|
||||
state->p_send.packets++;
|
||||
state->p_send.bytes += len +
|
||||
sshbuf_len(state->outgoing_packet);
|
||||
sshbuf_reset(state->outgoing_packet);
|
||||
|
||||
/*
|
||||
* Note that the packet is now only buffered in output. It won't be
|
||||
* actually sent until ssh_packet_write_wait or ssh_packet_write_poll
|
||||
* is called.
|
||||
*/
|
||||
r = 0;
|
||||
out:
|
||||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
ssh_set_newkeys(struct ssh *ssh, int mode)
|
||||
{
|
||||
@ -1397,13 +1304,6 @@ ssh_packet_read_seqnr(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
|
||||
r = ssh_packet_read_poll_seqnr(ssh, typep, seqnr_p);
|
||||
if (r != 0)
|
||||
break;
|
||||
if (!compat20 && (
|
||||
*typep == SSH_SMSG_SUCCESS
|
||||
|| *typep == SSH_SMSG_FAILURE
|
||||
|| *typep == SSH_CMSG_EOF
|
||||
|| *typep == SSH_CMSG_EXIT_CONFIRMATION))
|
||||
if ((r = sshpkt_get_end(ssh)) != 0)
|
||||
break;
|
||||
/* If we got a packet, return it. */
|
||||
if (*typep != SSH_MSG_NONE)
|
||||
break;
|
||||
@ -1924,75 +1824,48 @@ ssh_packet_read_poll_seqnr(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
|
||||
|
||||
for (;;) {
|
||||
msg = NULL;
|
||||
if (compat20) {
|
||||
r = ssh_packet_read_poll2(ssh, typep, seqnr_p);
|
||||
if (r != 0)
|
||||
r = ssh_packet_read_poll2(ssh, typep, seqnr_p);
|
||||
if (r != 0)
|
||||
return r;
|
||||
if (*typep) {
|
||||
state->keep_alive_timeouts = 0;
|
||||
DBG(debug("received packet type %d", *typep));
|
||||
}
|
||||
switch (*typep) {
|
||||
case SSH2_MSG_IGNORE:
|
||||
debug3("Received SSH2_MSG_IGNORE");
|
||||
break;
|
||||
case SSH2_MSG_DEBUG:
|
||||
if ((r = sshpkt_get_u8(ssh, NULL)) != 0 ||
|
||||
(r = sshpkt_get_string(ssh, &msg, NULL)) != 0 ||
|
||||
(r = sshpkt_get_string(ssh, NULL, NULL)) != 0) {
|
||||
free(msg);
|
||||
return r;
|
||||
if (*typep) {
|
||||
state->keep_alive_timeouts = 0;
|
||||
DBG(debug("received packet type %d", *typep));
|
||||
}
|
||||
switch (*typep) {
|
||||
case SSH2_MSG_IGNORE:
|
||||
debug3("Received SSH2_MSG_IGNORE");
|
||||
break;
|
||||
case SSH2_MSG_DEBUG:
|
||||
if ((r = sshpkt_get_u8(ssh, NULL)) != 0 ||
|
||||
(r = sshpkt_get_string(ssh, &msg, NULL)) != 0 ||
|
||||
(r = sshpkt_get_string(ssh, NULL, NULL)) != 0) {
|
||||
free(msg);
|
||||
return r;
|
||||
}
|
||||
debug("Remote: %.900s", msg);
|
||||
free(msg);
|
||||
break;
|
||||
case SSH2_MSG_DISCONNECT:
|
||||
if ((r = sshpkt_get_u32(ssh, &reason)) != 0 ||
|
||||
(r = sshpkt_get_string(ssh, &msg, NULL)) != 0)
|
||||
return r;
|
||||
/* Ignore normal client exit notifications */
|
||||
do_log2(ssh->state->server_side &&
|
||||
reason == SSH2_DISCONNECT_BY_APPLICATION ?
|
||||
SYSLOG_LEVEL_INFO : SYSLOG_LEVEL_ERROR,
|
||||
"Received disconnect from %s port %d:"
|
||||
"%u: %.400s", ssh_remote_ipaddr(ssh),
|
||||
ssh_remote_port(ssh), reason, msg);
|
||||
free(msg);
|
||||
return SSH_ERR_DISCONNECTED;
|
||||
case SSH2_MSG_UNIMPLEMENTED:
|
||||
if ((r = sshpkt_get_u32(ssh, &seqnr)) != 0)
|
||||
return r;
|
||||
debug("Received SSH2_MSG_UNIMPLEMENTED for %u",
|
||||
seqnr);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
r = ssh_packet_read_poll1(ssh, typep);
|
||||
switch (*typep) {
|
||||
case SSH_MSG_NONE:
|
||||
return SSH_MSG_NONE;
|
||||
case SSH_MSG_IGNORE:
|
||||
break;
|
||||
case SSH_MSG_DEBUG:
|
||||
if ((r = sshpkt_get_string(ssh, &msg, NULL)) != 0)
|
||||
return r;
|
||||
debug("Remote: %.900s", msg);
|
||||
free(msg);
|
||||
break;
|
||||
case SSH_MSG_DISCONNECT:
|
||||
if ((r = sshpkt_get_string(ssh, &msg, NULL)) != 0)
|
||||
return r;
|
||||
error("Received disconnect from %s port %d: "
|
||||
"%.400s", ssh_remote_ipaddr(ssh),
|
||||
ssh_remote_port(ssh), msg);
|
||||
free(msg);
|
||||
return SSH_ERR_DISCONNECTED;
|
||||
default:
|
||||
DBG(debug("received packet type %d", *typep));
|
||||
return 0;
|
||||
}
|
||||
debug("Remote: %.900s", msg);
|
||||
free(msg);
|
||||
break;
|
||||
case SSH2_MSG_DISCONNECT:
|
||||
if ((r = sshpkt_get_u32(ssh, &reason)) != 0 ||
|
||||
(r = sshpkt_get_string(ssh, &msg, NULL)) != 0)
|
||||
return r;
|
||||
/* Ignore normal client exit notifications */
|
||||
do_log2(ssh->state->server_side &&
|
||||
reason == SSH2_DISCONNECT_BY_APPLICATION ?
|
||||
SYSLOG_LEVEL_INFO : SYSLOG_LEVEL_ERROR,
|
||||
"Received disconnect from %s port %d:"
|
||||
"%u: %.400s", ssh_remote_ipaddr(ssh),
|
||||
ssh_remote_port(ssh), reason, msg);
|
||||
free(msg);
|
||||
return SSH_ERR_DISCONNECTED;
|
||||
case SSH2_MSG_UNIMPLEMENTED:
|
||||
if ((r = sshpkt_get_u32(ssh, &seqnr)) != 0)
|
||||
return r;
|
||||
debug("Received SSH2_MSG_UNIMPLEMENTED for %u",
|
||||
seqnr);
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2044,27 +1917,19 @@ ssh_packet_send_debug(struct ssh *ssh, const char *fmt,...)
|
||||
va_list args;
|
||||
int r;
|
||||
|
||||
if (compat20 && (ssh->compat & SSH_BUG_DEBUG))
|
||||
if ((ssh->compat & SSH_BUG_DEBUG))
|
||||
return;
|
||||
|
||||
va_start(args, fmt);
|
||||
vsnprintf(buf, sizeof(buf), fmt, args);
|
||||
va_end(args);
|
||||
|
||||
if (compat20) {
|
||||
if ((r = sshpkt_start(ssh, SSH2_MSG_DEBUG)) != 0 ||
|
||||
(r = sshpkt_put_u8(ssh, 0)) != 0 || /* always display */
|
||||
(r = sshpkt_put_cstring(ssh, buf)) != 0 ||
|
||||
(r = sshpkt_put_cstring(ssh, "")) != 0 ||
|
||||
(r = sshpkt_send(ssh)) != 0)
|
||||
fatal("%s: %s", __func__, ssh_err(r));
|
||||
} else {
|
||||
if ((r = sshpkt_start(ssh, SSH_MSG_DEBUG)) != 0 ||
|
||||
(r = sshpkt_put_cstring(ssh, buf)) != 0 ||
|
||||
(r = sshpkt_send(ssh)) != 0)
|
||||
fatal("%s: %s", __func__, ssh_err(r));
|
||||
}
|
||||
if ((r = ssh_packet_write_wait(ssh)) != 0)
|
||||
if ((r = sshpkt_start(ssh, SSH2_MSG_DEBUG)) != 0 ||
|
||||
(r = sshpkt_put_u8(ssh, 0)) != 0 || /* always display */
|
||||
(r = sshpkt_put_cstring(ssh, buf)) != 0 ||
|
||||
(r = sshpkt_put_cstring(ssh, "")) != 0 ||
|
||||
(r = sshpkt_send(ssh)) != 0 ||
|
||||
(r = ssh_packet_write_wait(ssh)) != 0)
|
||||
fatal("%s: %s", __func__, ssh_err(r));
|
||||
}
|
||||
|
||||
@ -2385,8 +2250,7 @@ ssh_packet_send_ignore(struct ssh *ssh, int nbytes)
|
||||
u_int32_t rnd = 0;
|
||||
int r, i;
|
||||
|
||||
if ((r = sshpkt_start(ssh, compat20 ?
|
||||
SSH2_MSG_IGNORE : SSH_MSG_IGNORE)) != 0 ||
|
||||
if ((r = sshpkt_start(ssh, SSH2_MSG_IGNORE)) != 0 ||
|
||||
(r = sshpkt_put_u32(ssh, nbytes)) != 0)
|
||||
fatal("%s: %s", __func__, ssh_err(r));
|
||||
for (i = 0; i < nbytes; i++) {
|
||||
@ -2531,38 +2395,22 @@ ssh_packet_get_state(struct ssh *ssh, struct sshbuf *m)
|
||||
struct session_state *state = ssh->state;
|
||||
u_char *p;
|
||||
size_t slen, rlen;
|
||||
int r, ssh1cipher;
|
||||
int r;
|
||||
|
||||
if (!compat20) {
|
||||
ssh1cipher = cipher_ctx_get_number(state->receive_context);
|
||||
slen = cipher_get_keyiv_len(state->send_context);
|
||||
rlen = cipher_get_keyiv_len(state->receive_context);
|
||||
if ((r = sshbuf_put_u32(m, state->remote_protocol_flags)) != 0 ||
|
||||
(r = sshbuf_put_u32(m, ssh1cipher)) != 0 ||
|
||||
(r = sshbuf_put_string(m, state->ssh1_key, state->ssh1_keylen)) != 0 ||
|
||||
(r = sshbuf_put_u32(m, slen)) != 0 ||
|
||||
(r = sshbuf_reserve(m, slen, &p)) != 0 ||
|
||||
(r = cipher_get_keyiv(state->send_context, p, slen)) != 0 ||
|
||||
(r = sshbuf_put_u32(m, rlen)) != 0 ||
|
||||
(r = sshbuf_reserve(m, rlen, &p)) != 0 ||
|
||||
(r = cipher_get_keyiv(state->receive_context, p, rlen)) != 0)
|
||||
return r;
|
||||
} else {
|
||||
if ((r = kex_to_blob(m, ssh->kex)) != 0 ||
|
||||
(r = newkeys_to_blob(m, ssh, MODE_OUT)) != 0 ||
|
||||
(r = newkeys_to_blob(m, ssh, MODE_IN)) != 0 ||
|
||||
(r = sshbuf_put_u64(m, state->rekey_limit)) != 0 ||
|
||||
(r = sshbuf_put_u32(m, state->rekey_interval)) != 0 ||
|
||||
(r = sshbuf_put_u32(m, state->p_send.seqnr)) != 0 ||
|
||||
(r = sshbuf_put_u64(m, state->p_send.blocks)) != 0 ||
|
||||
(r = sshbuf_put_u32(m, state->p_send.packets)) != 0 ||
|
||||
(r = sshbuf_put_u64(m, state->p_send.bytes)) != 0 ||
|
||||
(r = sshbuf_put_u32(m, state->p_read.seqnr)) != 0 ||
|
||||
(r = sshbuf_put_u64(m, state->p_read.blocks)) != 0 ||
|
||||
(r = sshbuf_put_u32(m, state->p_read.packets)) != 0 ||
|
||||
(r = sshbuf_put_u64(m, state->p_read.bytes)) != 0)
|
||||
return r;
|
||||
}
|
||||
if ((r = kex_to_blob(m, ssh->kex)) != 0 ||
|
||||
(r = newkeys_to_blob(m, ssh, MODE_OUT)) != 0 ||
|
||||
(r = newkeys_to_blob(m, ssh, MODE_IN)) != 0 ||
|
||||
(r = sshbuf_put_u64(m, state->rekey_limit)) != 0 ||
|
||||
(r = sshbuf_put_u32(m, state->rekey_interval)) != 0 ||
|
||||
(r = sshbuf_put_u32(m, state->p_send.seqnr)) != 0 ||
|
||||
(r = sshbuf_put_u64(m, state->p_send.blocks)) != 0 ||
|
||||
(r = sshbuf_put_u32(m, state->p_send.packets)) != 0 ||
|
||||
(r = sshbuf_put_u64(m, state->p_send.bytes)) != 0 ||
|
||||
(r = sshbuf_put_u32(m, state->p_read.seqnr)) != 0 ||
|
||||
(r = sshbuf_put_u64(m, state->p_read.blocks)) != 0 ||
|
||||
(r = sshbuf_put_u32(m, state->p_read.packets)) != 0 ||
|
||||
(r = sshbuf_put_u64(m, state->p_read.bytes)) != 0)
|
||||
return r;
|
||||
|
||||
slen = cipher_get_keycontext(state->send_context, NULL);
|
||||
rlen = cipher_get_keycontext(state->receive_context, NULL);
|
||||
@ -2701,53 +2549,34 @@ int
|
||||
ssh_packet_set_state(struct ssh *ssh, struct sshbuf *m)
|
||||
{
|
||||
struct session_state *state = ssh->state;
|
||||
const u_char *ssh1key, *ivin, *ivout, *keyin, *keyout, *input, *output;
|
||||
size_t ssh1keylen, rlen, slen, ilen, olen;
|
||||
const u_char *keyin, *keyout, *input, *output;
|
||||
size_t rlen, slen, ilen, olen;
|
||||
int r;
|
||||
u_int ssh1cipher = 0;
|
||||
|
||||
if (!compat20) {
|
||||
if ((r = sshbuf_get_u32(m, &state->remote_protocol_flags)) != 0 ||
|
||||
(r = sshbuf_get_u32(m, &ssh1cipher)) != 0 ||
|
||||
(r = sshbuf_get_string_direct(m, &ssh1key, &ssh1keylen)) != 0 ||
|
||||
(r = sshbuf_get_string_direct(m, &ivout, &slen)) != 0 ||
|
||||
(r = sshbuf_get_string_direct(m, &ivin, &rlen)) != 0)
|
||||
return r;
|
||||
if (ssh1cipher > INT_MAX)
|
||||
return SSH_ERR_KEY_UNKNOWN_CIPHER;
|
||||
ssh_packet_set_encryption_key(ssh, ssh1key, ssh1keylen,
|
||||
(int)ssh1cipher);
|
||||
if (cipher_get_keyiv_len(state->send_context) != (int)slen ||
|
||||
cipher_get_keyiv_len(state->receive_context) != (int)rlen)
|
||||
return SSH_ERR_INVALID_FORMAT;
|
||||
if ((r = cipher_set_keyiv(state->send_context, ivout)) != 0 ||
|
||||
(r = cipher_set_keyiv(state->receive_context, ivin)) != 0)
|
||||
return r;
|
||||
} else {
|
||||
if ((r = kex_from_blob(m, &ssh->kex)) != 0 ||
|
||||
(r = newkeys_from_blob(m, ssh, MODE_OUT)) != 0 ||
|
||||
(r = newkeys_from_blob(m, ssh, MODE_IN)) != 0 ||
|
||||
(r = sshbuf_get_u64(m, &state->rekey_limit)) != 0 ||
|
||||
(r = sshbuf_get_u32(m, &state->rekey_interval)) != 0 ||
|
||||
(r = sshbuf_get_u32(m, &state->p_send.seqnr)) != 0 ||
|
||||
(r = sshbuf_get_u64(m, &state->p_send.blocks)) != 0 ||
|
||||
(r = sshbuf_get_u32(m, &state->p_send.packets)) != 0 ||
|
||||
(r = sshbuf_get_u64(m, &state->p_send.bytes)) != 0 ||
|
||||
(r = sshbuf_get_u32(m, &state->p_read.seqnr)) != 0 ||
|
||||
(r = sshbuf_get_u64(m, &state->p_read.blocks)) != 0 ||
|
||||
(r = sshbuf_get_u32(m, &state->p_read.packets)) != 0 ||
|
||||
(r = sshbuf_get_u64(m, &state->p_read.bytes)) != 0)
|
||||
return r;
|
||||
/*
|
||||
* We set the time here so that in post-auth privsep slave we
|
||||
* count from the completion of the authentication.
|
||||
*/
|
||||
state->rekey_time = monotime();
|
||||
/* XXX ssh_set_newkeys overrides p_read.packets? XXX */
|
||||
if ((r = ssh_set_newkeys(ssh, MODE_IN)) != 0 ||
|
||||
(r = ssh_set_newkeys(ssh, MODE_OUT)) != 0)
|
||||
return r;
|
||||
}
|
||||
if ((r = kex_from_blob(m, &ssh->kex)) != 0 ||
|
||||
(r = newkeys_from_blob(m, ssh, MODE_OUT)) != 0 ||
|
||||
(r = newkeys_from_blob(m, ssh, MODE_IN)) != 0 ||
|
||||
(r = sshbuf_get_u64(m, &state->rekey_limit)) != 0 ||
|
||||
(r = sshbuf_get_u32(m, &state->rekey_interval)) != 0 ||
|
||||
(r = sshbuf_get_u32(m, &state->p_send.seqnr)) != 0 ||
|
||||
(r = sshbuf_get_u64(m, &state->p_send.blocks)) != 0 ||
|
||||
(r = sshbuf_get_u32(m, &state->p_send.packets)) != 0 ||
|
||||
(r = sshbuf_get_u64(m, &state->p_send.bytes)) != 0 ||
|
||||
(r = sshbuf_get_u32(m, &state->p_read.seqnr)) != 0 ||
|
||||
(r = sshbuf_get_u64(m, &state->p_read.blocks)) != 0 ||
|
||||
(r = sshbuf_get_u32(m, &state->p_read.packets)) != 0 ||
|
||||
(r = sshbuf_get_u64(m, &state->p_read.bytes)) != 0)
|
||||
return r;
|
||||
/*
|
||||
* We set the time here so that in post-auth privsep slave we
|
||||
* count from the completion of the authentication.
|
||||
*/
|
||||
state->rekey_time = monotime();
|
||||
/* XXX ssh_set_newkeys overrides p_read.packets? XXX */
|
||||
if ((r = ssh_set_newkeys(ssh, MODE_IN)) != 0 ||
|
||||
(r = ssh_set_newkeys(ssh, MODE_OUT)) != 0)
|
||||
return r;
|
||||
|
||||
if ((r = sshbuf_get_string_direct(m, &keyout, &slen)) != 0 ||
|
||||
(r = sshbuf_get_string_direct(m, &keyin, &rlen)) != 0)
|
||||
return r;
|
||||
@ -2925,15 +2754,13 @@ sshpkt_ptr(struct ssh *ssh, size_t *lenp)
|
||||
int
|
||||
sshpkt_start(struct ssh *ssh, u_char type)
|
||||
{
|
||||
u_char buf[9];
|
||||
int len;
|
||||
u_char buf[6]; /* u32 packet length, u8 pad len, u8 type */
|
||||
|
||||
DBG(debug("packet_start[%d]", type));
|
||||
len = compat20 ? 6 : 9;
|
||||
memset(buf, 0, len - 1);
|
||||
buf[len - 1] = type;
|
||||
memset(buf, 0, sizeof(buf));
|
||||
buf[sizeof(buf) - 1] = type;
|
||||
sshbuf_reset(ssh->state->outgoing_packet);
|
||||
return sshbuf_put(ssh->state->outgoing_packet, buf, len);
|
||||
return sshbuf_put(ssh->state->outgoing_packet, buf, sizeof(buf));
|
||||
}
|
||||
|
||||
static int
|
||||
@ -2973,10 +2800,7 @@ sshpkt_send(struct ssh *ssh)
|
||||
{
|
||||
if (ssh->state && ssh->state->mux)
|
||||
return ssh_packet_send_mux(ssh);
|
||||
if (compat20)
|
||||
return ssh_packet_send2(ssh);
|
||||
else
|
||||
return ssh_packet_send1(ssh);
|
||||
return ssh_packet_send2(ssh);
|
||||
}
|
||||
|
||||
int
|
||||
@ -2990,19 +2814,12 @@ sshpkt_disconnect(struct ssh *ssh, const char *fmt,...)
|
||||
vsnprintf(buf, sizeof(buf), fmt, args);
|
||||
va_end(args);
|
||||
|
||||
if (compat20) {
|
||||
if ((r = sshpkt_start(ssh, SSH2_MSG_DISCONNECT)) != 0 ||
|
||||
(r = sshpkt_put_u32(ssh, SSH2_DISCONNECT_PROTOCOL_ERROR)) != 0 ||
|
||||
(r = sshpkt_put_cstring(ssh, buf)) != 0 ||
|
||||
(r = sshpkt_put_cstring(ssh, "")) != 0 ||
|
||||
(r = sshpkt_send(ssh)) != 0)
|
||||
return r;
|
||||
} else {
|
||||
if ((r = sshpkt_start(ssh, SSH_MSG_DISCONNECT)) != 0 ||
|
||||
(r = sshpkt_put_cstring(ssh, buf)) != 0 ||
|
||||
(r = sshpkt_send(ssh)) != 0)
|
||||
return r;
|
||||
}
|
||||
if ((r = sshpkt_start(ssh, SSH2_MSG_DISCONNECT)) != 0 ||
|
||||
(r = sshpkt_put_u32(ssh, SSH2_DISCONNECT_PROTOCOL_ERROR)) != 0 ||
|
||||
(r = sshpkt_put_cstring(ssh, buf)) != 0 ||
|
||||
(r = sshpkt_put_cstring(ssh, "")) != 0 ||
|
||||
(r = sshpkt_send(ssh)) != 0)
|
||||
return r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
3
packet.h
3
packet.h
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: packet.h,v 1.76 2017/02/03 23:03:33 djm Exp $ */
|
||||
/* $OpenBSD: packet.h,v 1.77 2017/04/30 23:13:25 djm Exp $ */
|
||||
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
@ -112,7 +112,6 @@ int ssh_packet_set_log_preamble(struct ssh *, const char *, ...)
|
||||
|
||||
int ssh_packet_log_type(u_char);
|
||||
|
||||
int ssh_packet_send1(struct ssh *);
|
||||
int ssh_packet_send2_wrapped(struct ssh *);
|
||||
int ssh_packet_send2(struct ssh *);
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: ssh-keyscan.c,v 1.110 2017/04/30 23:10:43 djm Exp $ */
|
||||
/* $OpenBSD: ssh-keyscan.c,v 1.111 2017/04/30 23:13:25 djm Exp $ */
|
||||
/*
|
||||
* Copyright 1995, 1996 by David Mazieres <dm@lcs.mit.edu>.
|
||||
*
|
||||
@ -221,7 +221,6 @@ keygrab_ssh2(con *c)
|
||||
char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT };
|
||||
int r;
|
||||
|
||||
enable_compat20();
|
||||
switch (c->c_keytype) {
|
||||
case KT_DSA:
|
||||
myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ?
|
||||
|
174
ssh.c
174
ssh.c
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: ssh.c,v 1.454 2017/04/30 23:11:45 djm Exp $ */
|
||||
/* $OpenBSD: ssh.c,v 1.455 2017/04/30 23:13:25 djm Exp $ */
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
@ -209,7 +209,6 @@ usage(void)
|
||||
exit(255);
|
||||
}
|
||||
|
||||
static int ssh_session(void);
|
||||
static int ssh_session2(void);
|
||||
static void load_public_identity_files(void);
|
||||
static void main_sigchld_handler(int);
|
||||
@ -1243,7 +1242,6 @@ main(int ac, char **av)
|
||||
if ((sock = muxclient(options.control_path)) >= 0) {
|
||||
packet_set_connection(sock, sock);
|
||||
ssh = active_state; /* XXX */
|
||||
enable_compat20(); /* XXX */
|
||||
packet_set_mux();
|
||||
goto skip_connect;
|
||||
}
|
||||
@ -1447,7 +1445,7 @@ main(int ac, char **av)
|
||||
}
|
||||
|
||||
skip_connect:
|
||||
exit_status = compat20 ? ssh_session2() : ssh_session();
|
||||
exit_status = ssh_session2();
|
||||
packet_close();
|
||||
|
||||
if (options.control_path != NULL && muxserver_sock != -1)
|
||||
@ -1591,8 +1589,6 @@ ssh_init_stdio_forwarding(void)
|
||||
|
||||
if (options.stdio_forward_host == NULL)
|
||||
return;
|
||||
if (!compat20)
|
||||
fatal("stdio forwarding require Protocol 2");
|
||||
|
||||
debug3("%s: %s:%d", __func__, options.stdio_forward_host,
|
||||
options.stdio_forward_port);
|
||||
@ -1691,172 +1687,6 @@ check_agent_present(void)
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
ssh_session(void)
|
||||
{
|
||||
int type;
|
||||
int interactive = 0;
|
||||
int have_tty = 0;
|
||||
struct winsize ws;
|
||||
char *cp;
|
||||
const char *display;
|
||||
char *proto = NULL, *data = NULL;
|
||||
|
||||
/* Enable compression if requested. */
|
||||
if (options.compression) {
|
||||
debug("Requesting compression at level %d.",
|
||||
options.compression_level);
|
||||
|
||||
if (options.compression_level < 1 ||
|
||||
options.compression_level > 9)
|
||||
fatal("Compression level must be from 1 (fast) to "
|
||||
"9 (slow, best).");
|
||||
|
||||
/* Send the request. */
|
||||
packet_start(SSH_CMSG_REQUEST_COMPRESSION);
|
||||
packet_put_int(options.compression_level);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
type = packet_read();
|
||||
if (type == SSH_SMSG_SUCCESS)
|
||||
packet_start_compression(options.compression_level);
|
||||
else if (type == SSH_SMSG_FAILURE)
|
||||
logit("Warning: Remote host refused compression.");
|
||||
else
|
||||
packet_disconnect("Protocol error waiting for "
|
||||
"compression response.");
|
||||
}
|
||||
/* Allocate a pseudo tty if appropriate. */
|
||||
if (tty_flag) {
|
||||
debug("Requesting pty.");
|
||||
|
||||
/* Start the packet. */
|
||||
packet_start(SSH_CMSG_REQUEST_PTY);
|
||||
|
||||
/* Store TERM in the packet. There is no limit on the
|
||||
length of the string. */
|
||||
cp = getenv("TERM");
|
||||
if (!cp)
|
||||
cp = "";
|
||||
packet_put_cstring(cp);
|
||||
|
||||
/* Store window size in the packet. */
|
||||
if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0)
|
||||
memset(&ws, 0, sizeof(ws));
|
||||
packet_put_int((u_int)ws.ws_row);
|
||||
packet_put_int((u_int)ws.ws_col);
|
||||
packet_put_int((u_int)ws.ws_xpixel);
|
||||
packet_put_int((u_int)ws.ws_ypixel);
|
||||
|
||||
/* Store tty modes in the packet. */
|
||||
tty_make_modes(fileno(stdin), NULL);
|
||||
|
||||
/* Send the packet, and wait for it to leave. */
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
|
||||
/* Read response from the server. */
|
||||
type = packet_read();
|
||||
if (type == SSH_SMSG_SUCCESS) {
|
||||
interactive = 1;
|
||||
have_tty = 1;
|
||||
} else if (type == SSH_SMSG_FAILURE)
|
||||
logit("Warning: Remote host failed or refused to "
|
||||
"allocate a pseudo tty.");
|
||||
else
|
||||
packet_disconnect("Protocol error waiting for pty "
|
||||
"request response.");
|
||||
}
|
||||
/* Request X11 forwarding if enabled and DISPLAY is set. */
|
||||
display = getenv("DISPLAY");
|
||||
if (display == NULL && options.forward_x11)
|
||||
debug("X11 forwarding requested but DISPLAY not set");
|
||||
if (options.forward_x11 && client_x11_get_proto(display,
|
||||
options.xauth_location, options.forward_x11_trusted,
|
||||
options.forward_x11_timeout, &proto, &data) == 0) {
|
||||
/* Request forwarding with authentication spoofing. */
|
||||
debug("Requesting X11 forwarding with authentication "
|
||||
"spoofing.");
|
||||
x11_request_forwarding_with_spoofing(0, display, proto,
|
||||
data, 0);
|
||||
/* Read response from the server. */
|
||||
type = packet_read();
|
||||
if (type == SSH_SMSG_SUCCESS) {
|
||||
interactive = 1;
|
||||
} else if (type == SSH_SMSG_FAILURE) {
|
||||
logit("Warning: Remote host denied X11 forwarding.");
|
||||
} else {
|
||||
packet_disconnect("Protocol error waiting for X11 "
|
||||
"forwarding");
|
||||
}
|
||||
}
|
||||
/* Tell the packet module whether this is an interactive session. */
|
||||
packet_set_interactive(interactive,
|
||||
options.ip_qos_interactive, options.ip_qos_bulk);
|
||||
|
||||
/* Request authentication agent forwarding if appropriate. */
|
||||
check_agent_present();
|
||||
|
||||
if (options.forward_agent) {
|
||||
debug("Requesting authentication agent forwarding.");
|
||||
auth_request_forwarding();
|
||||
|
||||
/* Read response from the server. */
|
||||
type = packet_read();
|
||||
packet_check_eom();
|
||||
if (type != SSH_SMSG_SUCCESS)
|
||||
logit("Warning: Remote host denied authentication agent forwarding.");
|
||||
}
|
||||
|
||||
/* Initiate port forwardings. */
|
||||
ssh_init_stdio_forwarding();
|
||||
ssh_init_forwarding();
|
||||
|
||||
/* Execute a local command */
|
||||
if (options.local_command != NULL &&
|
||||
options.permit_local_command)
|
||||
ssh_local_cmd(options.local_command);
|
||||
|
||||
/*
|
||||
* If requested and we are not interested in replies to remote
|
||||
* forwarding requests, then let ssh continue in the background.
|
||||
*/
|
||||
if (fork_after_authentication_flag) {
|
||||
if (options.exit_on_forward_failure &&
|
||||
options.num_remote_forwards > 0) {
|
||||
debug("deferring postauth fork until remote forward "
|
||||
"confirmation received");
|
||||
} else
|
||||
fork_postauth();
|
||||
}
|
||||
|
||||
/*
|
||||
* If a command was specified on the command line, execute the
|
||||
* command now. Otherwise request the server to start a shell.
|
||||
*/
|
||||
if (buffer_len(&command) > 0) {
|
||||
int len = buffer_len(&command);
|
||||
if (len > 900)
|
||||
len = 900;
|
||||
debug("Sending command: %.*s", len,
|
||||
(u_char *)buffer_ptr(&command));
|
||||
packet_start(SSH_CMSG_EXEC_CMD);
|
||||
packet_put_string(buffer_ptr(&command), buffer_len(&command));
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
} else {
|
||||
debug("Requesting shell.");
|
||||
packet_start(SSH_CMSG_EXEC_SHELL);
|
||||
packet_send();
|
||||
packet_write_wait();
|
||||
}
|
||||
|
||||
/* Enter the interactive session. */
|
||||
return client_loop(have_tty, tty_flag ?
|
||||
options.escape_char : SSH_ESCAPECHAR_NONE, 0);
|
||||
}
|
||||
|
||||
/* request pty/x11/agent/tcpfwd/shell for channel */
|
||||
static void
|
||||
ssh_session2_setup(int id, int success, void *arg)
|
||||
{
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: ssh_api.c,v 1.7 2016/05/04 14:22:33 markus Exp $ */
|
||||
/* $OpenBSD: ssh_api.c,v 1.8 2017/04/30 23:13:25 djm Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2012 Markus Friedl. All rights reserved.
|
||||
*
|
||||
@ -371,7 +371,6 @@ _ssh_read_banner(struct ssh *ssh, char **bannerp)
|
||||
}
|
||||
if (remote_major != 2)
|
||||
return SSH_ERR_PROTOCOL_MISMATCH;
|
||||
enable_compat20();
|
||||
chop(buf);
|
||||
debug("Remote version string %.100s", buf);
|
||||
if ((*bannerp = strdup(buf)) == NULL)
|
||||
|
34
sshconnect.c
34
sshconnect.c
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: sshconnect.c,v 1.275 2017/04/30 23:11:45 djm Exp $ */
|
||||
/* $OpenBSD: sshconnect.c,v 1.276 2017/04/30 23:13:25 djm Exp $ */
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
@ -524,13 +524,8 @@ static void
|
||||
send_client_banner(int connection_out, int minor1)
|
||||
{
|
||||
/* Send our own protocol version identification. */
|
||||
if (compat20) {
|
||||
xasprintf(&client_version_string, "SSH-%d.%d-%.100s\r\n",
|
||||
PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2, SSH_VERSION);
|
||||
} else {
|
||||
xasprintf(&client_version_string, "SSH-%d.%d-%.100s\n",
|
||||
PROTOCOL_MAJOR_1, minor1, SSH_VERSION);
|
||||
}
|
||||
xasprintf(&client_version_string, "SSH-%d.%d-%.100s\r\n",
|
||||
PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2, SSH_VERSION);
|
||||
if (atomicio(vwrite, connection_out, client_version_string,
|
||||
strlen(client_version_string)) != strlen(client_version_string))
|
||||
fatal("write: %.100s", strerror(errno));
|
||||
@ -559,7 +554,6 @@ ssh_exchange_identification(int timeout_ms)
|
||||
fdsetsz = howmany(connection_in + 1, NFDBITS) * sizeof(fd_mask);
|
||||
fdset = xcalloc(1, fdsetsz);
|
||||
|
||||
enable_compat20();
|
||||
send_client_banner(connection_out, 0);
|
||||
client_banner_sent = 1;
|
||||
|
||||
@ -628,14 +622,11 @@ ssh_exchange_identification(int timeout_ms)
|
||||
mismatch = 0;
|
||||
|
||||
switch (remote_major) {
|
||||
case 1:
|
||||
if (remote_minor == 99)
|
||||
enable_compat20();
|
||||
else
|
||||
mismatch = 1;
|
||||
break;
|
||||
case 2:
|
||||
enable_compat20();
|
||||
break;
|
||||
case 1:
|
||||
if (remote_minor != 99)
|
||||
mismatch = 1;
|
||||
break;
|
||||
default:
|
||||
mismatch = 1;
|
||||
@ -1243,8 +1234,7 @@ verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
|
||||
host_key->cert->principals[i]);
|
||||
}
|
||||
} else {
|
||||
debug("Server host key: %s %s", compat20 ?
|
||||
sshkey_ssh_name(host_key) : sshkey_type(host_key), fp);
|
||||
debug("Server host key: %s %s", sshkey_ssh_name(host_key), fp);
|
||||
}
|
||||
|
||||
if (sshkey_equal(previous_host_key, host_key)) {
|
||||
@ -1349,12 +1339,8 @@ ssh_login(Sensitive *sensitive, const char *orighost,
|
||||
/* key exchange */
|
||||
/* authenticate user */
|
||||
debug("Authenticating to %s:%d as '%s'", host, port, server_user);
|
||||
if (compat20) {
|
||||
ssh_kex2(host, hostaddr, port);
|
||||
ssh_userauth2(local_user, server_user, host, sensitive);
|
||||
} else {
|
||||
fatal("ssh1 is not supported");
|
||||
}
|
||||
ssh_kex2(host, hostaddr, port);
|
||||
ssh_userauth2(local_user, server_user, host, sensitive);
|
||||
free(local_user);
|
||||
}
|
||||
|
||||
|
8
sshd.c
8
sshd.c
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: sshd.c,v 1.485 2017/03/15 03:52:30 deraadt Exp $ */
|
||||
/* $OpenBSD: sshd.c,v 1.486 2017/04/30 23:13:25 djm Exp $ */
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
@ -450,10 +450,8 @@ sshd_exchange_identification(struct ssh *ssh, int sock_in, int sock_out)
|
||||
chop(server_version_string);
|
||||
debug("Local version string %.200s", server_version_string);
|
||||
|
||||
if (remote_major == 2 ||
|
||||
(remote_major == 1 && remote_minor == 99)) {
|
||||
enable_compat20();
|
||||
} else {
|
||||
if (remote_major != 2 ||
|
||||
(remote_major == 1 && remote_minor != 99)) {
|
||||
s = "Protocol major versions differ.\n";
|
||||
(void) atomicio(vwrite, sock_out, s, strlen(s));
|
||||
close(sock_in);
|
||||
|
104
ttymodes.c
104
ttymodes.c
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: ttymodes.c,v 1.30 2016/05/04 14:22:33 markus Exp $ */
|
||||
/* $OpenBSD: ttymodes.c,v 1.31 2017/04/30 23:13:25 djm Exp $ */
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
@ -283,18 +283,10 @@ tty_make_modes(int fd, struct termios *tiop)
|
||||
int baud;
|
||||
Buffer buf;
|
||||
int tty_op_ospeed, tty_op_ispeed;
|
||||
void (*put_arg)(Buffer *, u_int);
|
||||
|
||||
buffer_init(&buf);
|
||||
if (compat20) {
|
||||
tty_op_ospeed = TTY_OP_OSPEED_PROTO2;
|
||||
tty_op_ispeed = TTY_OP_ISPEED_PROTO2;
|
||||
put_arg = buffer_put_int;
|
||||
} else {
|
||||
tty_op_ospeed = TTY_OP_OSPEED_PROTO1;
|
||||
tty_op_ispeed = TTY_OP_ISPEED_PROTO1;
|
||||
put_arg = (void (*)(Buffer *, u_int)) buffer_put_char;
|
||||
}
|
||||
tty_op_ospeed = TTY_OP_OSPEED_PROTO2;
|
||||
tty_op_ispeed = TTY_OP_ISPEED_PROTO2;
|
||||
|
||||
if (tiop == NULL) {
|
||||
if (fd == -1) {
|
||||
@ -319,11 +311,11 @@ tty_make_modes(int fd, struct termios *tiop)
|
||||
/* Store values of mode flags. */
|
||||
#define TTYCHAR(NAME, OP) \
|
||||
buffer_put_char(&buf, OP); \
|
||||
put_arg(&buf, special_char_encode(tio.c_cc[NAME]));
|
||||
buffer_put_int(&buf, special_char_encode(tio.c_cc[NAME]));
|
||||
|
||||
#define TTYMODE(NAME, FIELD, OP) \
|
||||
buffer_put_char(&buf, OP); \
|
||||
put_arg(&buf, ((tio.FIELD & NAME) != 0));
|
||||
buffer_put_int(&buf, ((tio.FIELD & NAME) != 0));
|
||||
|
||||
#include "ttymodes.h"
|
||||
|
||||
@ -333,10 +325,7 @@ tty_make_modes(int fd, struct termios *tiop)
|
||||
end:
|
||||
/* Mark end of mode data. */
|
||||
buffer_put_char(&buf, TTY_OP_END);
|
||||
if (compat20)
|
||||
packet_put_string(buffer_ptr(&buf), buffer_len(&buf));
|
||||
else
|
||||
packet_put_raw(buffer_ptr(&buf), buffer_len(&buf));
|
||||
packet_put_string(buffer_ptr(&buf), buffer_len(&buf));
|
||||
buffer_free(&buf);
|
||||
}
|
||||
|
||||
@ -351,19 +340,10 @@ tty_parse_modes(int fd, int *n_bytes_ptr)
|
||||
int opcode, baud;
|
||||
int n_bytes = 0;
|
||||
int failure = 0;
|
||||
u_int (*get_arg)(void);
|
||||
int arg_size;
|
||||
|
||||
if (compat20) {
|
||||
*n_bytes_ptr = packet_get_int();
|
||||
if (*n_bytes_ptr == 0)
|
||||
return;
|
||||
get_arg = packet_get_int;
|
||||
arg_size = 4;
|
||||
} else {
|
||||
get_arg = packet_get_char;
|
||||
arg_size = 1;
|
||||
}
|
||||
*n_bytes_ptr = packet_get_int();
|
||||
if (*n_bytes_ptr == 0)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Get old attributes for the terminal. We will modify these
|
||||
@ -404,13 +384,13 @@ tty_parse_modes(int fd, int *n_bytes_ptr)
|
||||
|
||||
#define TTYCHAR(NAME, OP) \
|
||||
case OP: \
|
||||
n_bytes += arg_size; \
|
||||
tio.c_cc[NAME] = special_char_decode(get_arg()); \
|
||||
n_bytes += 4; \
|
||||
tio.c_cc[NAME] = special_char_decode(packet_get_int()); \
|
||||
break;
|
||||
#define TTYMODE(NAME, FIELD, OP) \
|
||||
case OP: \
|
||||
n_bytes += arg_size; \
|
||||
if (get_arg()) \
|
||||
n_bytes += 4; \
|
||||
if (packet_get_int()) \
|
||||
tio.FIELD |= NAME; \
|
||||
else \
|
||||
tio.FIELD &= ~NAME; \
|
||||
@ -424,51 +404,21 @@ tty_parse_modes(int fd, int *n_bytes_ptr)
|
||||
default:
|
||||
debug("Ignoring unsupported tty mode opcode %d (0x%x)",
|
||||
opcode, opcode);
|
||||
if (!compat20) {
|
||||
/*
|
||||
* SSH1:
|
||||
* Opcodes 1 to 127 are defined to have
|
||||
* a one-byte argument.
|
||||
* Opcodes 128 to 159 are defined to have
|
||||
* an integer argument.
|
||||
*/
|
||||
if (opcode > 0 && opcode < 128) {
|
||||
n_bytes += 1;
|
||||
(void) packet_get_char();
|
||||
break;
|
||||
} else if (opcode >= 128 && opcode < 160) {
|
||||
n_bytes += 4;
|
||||
(void) packet_get_int();
|
||||
break;
|
||||
} else {
|
||||
/*
|
||||
* It is a truly undefined opcode (160 to 255).
|
||||
* We have no idea about its arguments. So we
|
||||
* must stop parsing. Note that some data
|
||||
* may be left in the packet; hopefully there
|
||||
* is nothing more coming after the mode data.
|
||||
*/
|
||||
logit("parse_tty_modes: unknown opcode %d",
|
||||
opcode);
|
||||
goto set;
|
||||
}
|
||||
/*
|
||||
* SSH2:
|
||||
* Opcodes 1 to 159 are defined to have a uint32
|
||||
* argument.
|
||||
* Opcodes 160 to 255 are undefined and cause parsing
|
||||
* to stop.
|
||||
*/
|
||||
if (opcode > 0 && opcode < 160) {
|
||||
n_bytes += 4;
|
||||
(void) packet_get_int();
|
||||
break;
|
||||
} else {
|
||||
/*
|
||||
* SSH2:
|
||||
* Opcodes 1 to 159 are defined to have
|
||||
* a uint32 argument.
|
||||
* Opcodes 160 to 255 are undefined and
|
||||
* cause parsing to stop.
|
||||
*/
|
||||
if (opcode > 0 && opcode < 160) {
|
||||
n_bytes += 4;
|
||||
(void) packet_get_int();
|
||||
break;
|
||||
} else {
|
||||
logit("parse_tty_modes: unknown opcode %d",
|
||||
opcode);
|
||||
goto set;
|
||||
}
|
||||
logit("parse_tty_modes: unknown opcode %d",
|
||||
opcode);
|
||||
goto set;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user