upstream commit

avoid more fatal/exit in the packet.c paths that
 ssh-keyscan uses; feedback and "looks good" markus@
This commit is contained in:
djm@openbsd.org 2015-01-30 01:13:33 +00:00 committed by Damien Miller
parent 669aee9943
commit 4509b5d4a4
9 changed files with 204 additions and 114 deletions

View File

@ -1,4 +1,4 @@
/* $OpenBSD: dispatch.c,v 1.24 2015/01/28 22:05:31 djm Exp $ */ /* $OpenBSD: dispatch.c,v 1.25 2015/01/30 01:13:33 djm Exp $ */
/* /*
* Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2000 Markus Friedl. All rights reserved.
* *
@ -49,9 +49,9 @@ dispatch_protocol_error(int type, u_int32_t seq, void *ctx)
fatal("protocol error"); fatal("protocol error");
if ((r = sshpkt_start(ssh, SSH2_MSG_UNIMPLEMENTED)) != 0 || if ((r = sshpkt_start(ssh, SSH2_MSG_UNIMPLEMENTED)) != 0 ||
(r = sshpkt_put_u32(ssh, seq)) != 0 || (r = sshpkt_put_u32(ssh, seq)) != 0 ||
(r = sshpkt_send(ssh)) != 0) (r = sshpkt_send(ssh)) != 0 ||
fatal("%s: %s", __func__, ssh_err(r)); (r = ssh_packet_write_wait(ssh)) != 0)
ssh_packet_write_wait(ssh); sshpkt_fatal(ssh, __func__, r);
return 0; return 0;
} }

View File

@ -223,6 +223,8 @@ void
packet_set_connection(int fd_in, int fd_out) packet_set_connection(int fd_in, int fd_out)
{ {
active_state = ssh_packet_set_connection(active_state, fd_in, fd_out); active_state = ssh_packet_set_connection(active_state, fd_in, fd_out);
if (active_state == NULL)
fatal("%s: ssh_packet_set_connection failed", __func__);
} }
void void
@ -255,20 +257,8 @@ packet_read_seqnr(u_int32_t *seqnr)
u_char type; u_char type;
int r; int r;
if ((r = ssh_packet_read_seqnr(active_state, &type, seqnr)) != 0) { if ((r = ssh_packet_read_seqnr(active_state, &type, seqnr)) != 0)
switch (r) { sshpkt_fatal(active_state, __func__, r);
case SSH_ERR_CONN_CLOSED:
logit("Connection closed by %.200s",
ssh_remote_ipaddr(active_state));
cleanup_exit(255);
case SSH_ERR_CONN_TIMEOUT:
logit("Connection to %.200s timed out while "
"waiting to read", ssh_remote_ipaddr(active_state));
cleanup_exit(255);
default:
fatal("%s: %s", __func__, ssh_err(r));
}
}
return type; return type;
} }
@ -279,7 +269,7 @@ packet_read_poll_seqnr(u_int32_t *seqnr)
int r; int r;
if ((r = ssh_packet_read_poll_seqnr(active_state, &type, seqnr))) if ((r = ssh_packet_read_poll_seqnr(active_state, &type, seqnr)))
fatal("%s: %s", __func__, ssh_err(r)); sshpkt_fatal(active_state, __func__, r);
return type; return type;
} }
@ -296,5 +286,32 @@ packet_process_incoming(const char *buf, u_int len)
int r; int r;
if ((r = ssh_packet_process_incoming(active_state, buf, len)) != 0) if ((r = ssh_packet_process_incoming(active_state, buf, len)) != 0)
fatal("%s: %s", __func__, ssh_err(r)); sshpkt_fatal(active_state, __func__, r);
}
void
packet_write_wait(void)
{
int r;
if ((r = ssh_packet_write_wait(active_state)) != 0)
sshpkt_fatal(active_state, __func__, r);
}
void
packet_write_poll(void)
{
int r;
if ((r = ssh_packet_write_poll(active_state)) != 0)
sshpkt_fatal(active_state, __func__, r);
}
void
packet_read_expect(int expected_type)
{
int r;
if ((r = ssh_packet_read_expect(active_state, expected_type)) != 0)
sshpkt_fatal(active_state, __func__, r);
} }

View File

@ -45,6 +45,9 @@ void packet_set_connection(int, int);
int packet_read_seqnr(u_int32_t *); int packet_read_seqnr(u_int32_t *);
int packet_read_poll_seqnr(u_int32_t *); int packet_read_poll_seqnr(u_int32_t *);
void packet_process_incoming(const char *buf, u_int len); void packet_process_incoming(const char *buf, u_int len);
void packet_write_wait(void);
void packet_write_poll(void);
void packet_read_expect(int expected_type);
#define packet_set_timeout(timeout, count) \ #define packet_set_timeout(timeout, count) \
ssh_packet_set_timeout(active_state, (timeout), (count)) ssh_packet_set_timeout(active_state, (timeout), (count))
#define packet_connection_is_on_socket() \ #define packet_connection_is_on_socket() \
@ -85,8 +88,6 @@ void packet_process_incoming(const char *buf, u_int len);
ssh_packet_send(active_state) ssh_packet_send(active_state)
#define packet_read() \ #define packet_read() \
ssh_packet_read(active_state) ssh_packet_read(active_state)
#define packet_read_expect(expected_type) \
ssh_packet_read_expect(active_state, (expected_type))
#define packet_get_int64() \ #define packet_get_int64() \
ssh_packet_get_int64(active_state) ssh_packet_get_int64(active_state)
#define packet_get_bignum(value) \ #define packet_get_bignum(value) \
@ -105,10 +106,6 @@ void packet_process_incoming(const char *buf, u_int len);
ssh_packet_send_debug(active_state, (fmt), ##args) ssh_packet_send_debug(active_state, (fmt), ##args)
#define packet_disconnect(fmt, args...) \ #define packet_disconnect(fmt, args...) \
ssh_packet_disconnect(active_state, (fmt), ##args) ssh_packet_disconnect(active_state, (fmt), ##args)
#define packet_write_poll() \
ssh_packet_write_poll(active_state)
#define packet_write_wait() \
ssh_packet_write_wait(active_state)
#define packet_have_data_to_write() \ #define packet_have_data_to_write() \
ssh_packet_have_data_to_write(active_state) ssh_packet_have_data_to_write(active_state)
#define packet_not_very_much_data_to_write() \ #define packet_not_very_much_data_to_write() \

220
packet.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: packet.c,v 1.204 2015/01/28 21:15:47 djm Exp $ */ /* $OpenBSD: packet.c,v 1.205 2015/01/30 01:13:33 djm Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@ -272,20 +272,26 @@ ssh_packet_set_connection(struct ssh *ssh, int fd_in, int fd_out)
const struct sshcipher *none = cipher_by_name("none"); const struct sshcipher *none = cipher_by_name("none");
int r; int r;
if (none == NULL) if (none == NULL) {
fatal("%s: cannot load cipher 'none'", __func__); error("%s: cannot load cipher 'none'", __func__);
return NULL;
}
if (ssh == NULL) if (ssh == NULL)
ssh = ssh_alloc_session_state(); ssh = ssh_alloc_session_state();
if (ssh == NULL) if (ssh == NULL) {
fatal("%s: cound not allocate state", __func__); error("%s: cound not allocate state", __func__);
return NULL;
}
state = ssh->state; state = ssh->state;
state->connection_in = fd_in; state->connection_in = fd_in;
state->connection_out = fd_out; state->connection_out = fd_out;
if ((r = cipher_init(&state->send_context, none, if ((r = cipher_init(&state->send_context, none,
(const u_char *)"", 0, NULL, 0, CIPHER_ENCRYPT)) != 0 || (const u_char *)"", 0, NULL, 0, CIPHER_ENCRYPT)) != 0 ||
(r = cipher_init(&state->receive_context, none, (r = cipher_init(&state->receive_context, none,
(const u_char *)"", 0, NULL, 0, CIPHER_DECRYPT)) != 0) (const u_char *)"", 0, NULL, 0, CIPHER_DECRYPT)) != 0) {
fatal("%s: cipher_init failed: %s", __func__, ssh_err(r)); error("%s: cipher_init failed: %s", __func__, ssh_err(r));
return NULL;
}
state->newkeys[MODE_IN] = state->newkeys[MODE_OUT] = NULL; state->newkeys[MODE_IN] = state->newkeys[MODE_OUT] = NULL;
deattack_init(&state->deattack); deattack_init(&state->deattack);
return ssh; return ssh;
@ -893,8 +899,8 @@ ssh_packet_send1(struct ssh *ssh)
/* /*
* Note that the packet is now only buffered in output. It won't be * Note that the packet is now only buffered in output. It won't be
* actually sent until packet_write_wait or packet_write_poll is * actually sent until ssh_packet_write_wait or ssh_packet_write_poll
* called. * is called.
*/ */
r = 0; r = 0;
out: out:
@ -1263,8 +1269,12 @@ ssh_packet_read_seqnr(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
if (setp == NULL) if (setp == NULL)
return SSH_ERR_ALLOC_FAIL; return SSH_ERR_ALLOC_FAIL;
/* Since we are blocking, ensure that all written packets have been sent. */ /*
ssh_packet_write_wait(ssh); * Since we are blocking, ensure that all written packets have
* been sent.
*/
if ((r = ssh_packet_write_wait(ssh)) != 0)
return r;
/* Stay in the loop until we have received a complete packet. */ /* Stay in the loop until we have received a complete packet. */
for (;;) { for (;;) {
@ -1351,16 +1361,22 @@ ssh_packet_read(struct ssh *ssh)
* that given, and gives a fatal error and exits if there is a mismatch. * that given, and gives a fatal error and exits if there is a mismatch.
*/ */
void int
ssh_packet_read_expect(struct ssh *ssh, int expected_type) ssh_packet_read_expect(struct ssh *ssh, u_int expected_type)
{ {
int type; int r;
u_char type;
type = ssh_packet_read(ssh); if ((r = ssh_packet_read_seqnr(ssh, &type, NULL)) != 0)
if (type != expected_type) return r;
ssh_packet_disconnect(ssh, if (type != expected_type) {
if ((r = sshpkt_disconnect(ssh,
"Protocol error: expected packet type %d, got %d", "Protocol error: expected packet type %d, got %d",
expected_type, type); expected_type, type)) != 0)
return r;
return SSH_ERR_PROTOCOL_ERROR;
}
return 0;
} }
/* Checks if a full packet is available in the data received so far via /* Checks if a full packet is available in the data received so far via
@ -1377,6 +1393,7 @@ ssh_packet_read_poll1(struct ssh *ssh, u_char *typep)
{ {
struct session_state *state = ssh->state; struct session_state *state = ssh->state;
u_int len, padded_len; u_int len, padded_len;
const char *emsg;
const u_char *cp; const u_char *cp;
u_char *p; u_char *p;
u_int checksum, stored_checksum; u_int checksum, stored_checksum;
@ -1389,9 +1406,12 @@ ssh_packet_read_poll1(struct ssh *ssh, u_char *typep)
return 0; return 0;
/* Get length of incoming packet. */ /* Get length of incoming packet. */
len = PEEK_U32(sshbuf_ptr(state->input)); len = PEEK_U32(sshbuf_ptr(state->input));
if (len < 1 + 2 + 2 || len > 256 * 1024) if (len < 1 + 2 + 2 || len > 256 * 1024) {
ssh_packet_disconnect(ssh, "Bad packet length %u.", if ((r = sshpkt_disconnect(ssh, "Bad packet length %u",
len); len)) != 0)
return r;
return SSH_ERR_CONN_CORRUPT;
}
padded_len = (len + 8) & ~7; padded_len = (len + 8) & ~7;
/* Check if the packet has been entirely received. */ /* Check if the packet has been entirely received. */
@ -1410,19 +1430,27 @@ ssh_packet_read_poll1(struct ssh *ssh, u_char *typep)
* Ariel Futoransky(futo@core-sdi.com) * Ariel Futoransky(futo@core-sdi.com)
*/ */
if (!state->receive_context.plaintext) { if (!state->receive_context.plaintext) {
emsg = NULL;
switch (detect_attack(&state->deattack, switch (detect_attack(&state->deattack,
sshbuf_ptr(state->input), padded_len)) { sshbuf_ptr(state->input), padded_len)) {
case DEATTACK_OK: case DEATTACK_OK:
break; break;
case DEATTACK_DETECTED: case DEATTACK_DETECTED:
ssh_packet_disconnect(ssh, emsg = "crc32 compensation attack detected";
"crc32 compensation attack: network attack detected" break;
);
case DEATTACK_DOS_DETECTED: case DEATTACK_DOS_DETECTED:
ssh_packet_disconnect(ssh, emsg = "deattack denial of service detected";
"deattack denial of service detected"); break;
default: default:
ssh_packet_disconnect(ssh, "deattack error"); emsg = "deattack error";
break;
}
if (emsg != NULL) {
error("%s", emsg);
if ((r = sshpkt_disconnect(ssh, "%s", emsg)) != 0 ||
(r = ssh_packet_write_wait(ssh)) != 0)
return r;
return SSH_ERR_CONN_CORRUPT;
} }
} }
@ -1451,16 +1479,24 @@ ssh_packet_read_poll1(struct ssh *ssh, u_char *typep)
goto out; goto out;
/* Test check bytes. */ /* Test check bytes. */
if (len != sshbuf_len(state->incoming_packet)) if (len != sshbuf_len(state->incoming_packet)) {
ssh_packet_disconnect(ssh, error("%s: len %d != sshbuf_len %zd", __func__,
"packet_read_poll1: len %d != sshbuf_len %zd.",
len, sshbuf_len(state->incoming_packet)); len, sshbuf_len(state->incoming_packet));
if ((r = sshpkt_disconnect(ssh, "invalid packet length")) != 0 ||
(r = ssh_packet_write_wait(ssh)) != 0)
return r;
return SSH_ERR_CONN_CORRUPT;
}
cp = sshbuf_ptr(state->incoming_packet) + len - 4; cp = sshbuf_ptr(state->incoming_packet) + len - 4;
stored_checksum = PEEK_U32(cp); stored_checksum = PEEK_U32(cp);
if (checksum != stored_checksum) if (checksum != stored_checksum) {
ssh_packet_disconnect(ssh, error("Corrupted check bytes on input");
"Corrupted check bytes on input."); if ((r = sshpkt_disconnect(ssh, "connection corrupted")) != 0 ||
(r = ssh_packet_write_wait(ssh)) != 0)
return r;
return SSH_ERR_CONN_CORRUPT;
}
if ((r = sshbuf_consume_end(state->incoming_packet, 4)) < 0) if ((r = sshbuf_consume_end(state->incoming_packet, 4)) < 0)
goto out; goto out;
@ -1478,9 +1514,13 @@ ssh_packet_read_poll1(struct ssh *ssh, u_char *typep)
state->p_read.bytes += padded_len + 4; state->p_read.bytes += padded_len + 4;
if ((r = sshbuf_get_u8(state->incoming_packet, typep)) != 0) if ((r = sshbuf_get_u8(state->incoming_packet, typep)) != 0)
goto out; goto out;
if (*typep < SSH_MSG_MIN || *typep > SSH_MSG_MAX) if (*typep < SSH_MSG_MIN || *typep > SSH_MSG_MAX) {
ssh_packet_disconnect(ssh, error("Invalid ssh1 packet type: %d", *typep);
"Invalid ssh1 packet type: %d", *typep); if ((r = sshpkt_disconnect(ssh, "invalid packet type")) != 0 ||
(r = ssh_packet_write_wait(ssh)) != 0)
return r;
return SSH_ERR_PROTOCOL_ERROR;
}
r = 0; r = 0;
out: out:
return r; return r;
@ -1634,7 +1674,6 @@ ssh_packet_read_poll2(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
if ((r = sshbuf_consume(state->input, mac->mac_len)) != 0) if ((r = sshbuf_consume(state->input, mac->mac_len)) != 0)
goto out; goto out;
} }
/* XXX now it's safe to use fatal/packet_disconnect */
if (seqnr_p != NULL) if (seqnr_p != NULL)
*seqnr_p = state->p_read.seqnr; *seqnr_p = state->p_read.seqnr;
if (++state->p_read.seqnr == 0) if (++state->p_read.seqnr == 0)
@ -1648,9 +1687,13 @@ ssh_packet_read_poll2(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
/* get padlen */ /* get padlen */
padlen = sshbuf_ptr(state->incoming_packet)[4]; padlen = sshbuf_ptr(state->incoming_packet)[4];
DBG(debug("input: padlen %d", padlen)); DBG(debug("input: padlen %d", padlen));
if (padlen < 4) if (padlen < 4) {
ssh_packet_disconnect(ssh, if ((r = sshpkt_disconnect(ssh,
"Corrupted padlen %d on input.", padlen); "Corrupted padlen %d on input.", padlen)) != 0 ||
(r = ssh_packet_write_wait(ssh)) != 0)
return r;
return SSH_ERR_CONN_CORRUPT;
}
/* skip packet size + padlen, discard padding */ /* skip packet size + padlen, discard padding */
if ((r = sshbuf_consume(state->incoming_packet, 4 + 1)) != 0 || if ((r = sshbuf_consume(state->incoming_packet, 4 + 1)) != 0 ||
@ -1677,9 +1720,13 @@ ssh_packet_read_poll2(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
*/ */
if ((r = sshbuf_get_u8(state->incoming_packet, typep)) != 0) if ((r = sshbuf_get_u8(state->incoming_packet, typep)) != 0)
goto out; goto out;
if (*typep < SSH2_MSG_MIN || *typep >= SSH2_MSG_LOCAL_MIN) if (*typep < SSH2_MSG_MIN || *typep >= SSH2_MSG_LOCAL_MIN) {
ssh_packet_disconnect(ssh, if ((r = sshpkt_disconnect(ssh,
"Invalid ssh2 packet type: %d", *typep); "Invalid ssh2 packet type: %d", *typep)) != 0 ||
(r = ssh_packet_write_wait(ssh)) != 0)
return r;
return SSH_ERR_PROTOCOL_ERROR;
}
if (*typep == SSH2_MSG_NEWKEYS) if (*typep == SSH2_MSG_NEWKEYS)
r = ssh_set_newkeys(ssh, MODE_IN); r = ssh_set_newkeys(ssh, MODE_IN);
else if (*typep == SSH2_MSG_USERAUTH_SUCCESS && !state->server_side) else if (*typep == SSH2_MSG_USERAUTH_SUCCESS && !state->server_side)
@ -1816,9 +1863,8 @@ ssh_packet_remaining(struct ssh *ssh)
* message is printed immediately, but only if the client is being executed * message is printed immediately, but only if the client is being executed
* in verbose mode. These messages are primarily intended to ease debugging * in verbose mode. These messages are primarily intended to ease debugging
* authentication problems. The length of the formatted message must not * authentication problems. The length of the formatted message must not
* exceed 1024 bytes. This will automatically call packet_write_wait. * exceed 1024 bytes. This will automatically call ssh_packet_write_wait.
*/ */
void void
ssh_packet_send_debug(struct ssh *ssh, const char *fmt,...) ssh_packet_send_debug(struct ssh *ssh, const char *fmt,...)
{ {
@ -1846,7 +1892,29 @@ ssh_packet_send_debug(struct ssh *ssh, const char *fmt,...)
(r = sshpkt_send(ssh)) != 0) (r = sshpkt_send(ssh)) != 0)
fatal("%s: %s", __func__, ssh_err(r)); fatal("%s: %s", __func__, ssh_err(r));
} }
ssh_packet_write_wait(ssh); if ((r = ssh_packet_write_wait(ssh)) != 0)
fatal("%s: %s", __func__, ssh_err(r));
}
/*
* Pretty-print connection-terminating errors and exit.
*/
void
sshpkt_fatal(struct ssh *ssh, const char *tag, int r)
{
switch (r) {
case SSH_ERR_CONN_CLOSED:
logit("Connection closed by %.200s", ssh_remote_ipaddr(ssh));
cleanup_exit(255);
case SSH_ERR_CONN_TIMEOUT:
logit("Connection to %.200s timed out while "
"waiting to write", ssh_remote_ipaddr(ssh));
cleanup_exit(255);
default:
fatal("%s%sConnection to %.200s: %s",
tag != NULL ? tag : "", tag != NULL ? ": " : "",
ssh_remote_ipaddr(ssh), ssh_err(r));
}
} }
/* /*
@ -1855,7 +1923,6 @@ ssh_packet_send_debug(struct ssh *ssh, const char *fmt,...)
* should not contain a newline. The length of the formatted message must * should not contain a newline. The length of the formatted message must
* not exceed 1024 bytes. * not exceed 1024 bytes.
*/ */
void void
ssh_packet_disconnect(struct ssh *ssh, const char *fmt,...) ssh_packet_disconnect(struct ssh *ssh, const char *fmt,...)
{ {
@ -1879,30 +1946,26 @@ ssh_packet_disconnect(struct ssh *ssh, const char *fmt,...)
/* Display the error locally */ /* Display the error locally */
logit("Disconnecting: %.100s", buf); logit("Disconnecting: %.100s", buf);
/* Send the disconnect message to the other side, and wait for it to get sent. */ /*
if (compat20) { * Send the disconnect message to the other side, and wait
if ((r = sshpkt_start(ssh, SSH2_MSG_DISCONNECT)) != 0 || * for it to get sent.
(r = sshpkt_put_u32(ssh, SSH2_DISCONNECT_PROTOCOL_ERROR)) != 0 || */
(r = sshpkt_put_cstring(ssh, buf)) != 0 || if ((r = sshpkt_disconnect(ssh, "%s", buf)) != 0)
(r = sshpkt_put_cstring(ssh, "")) != 0 || sshpkt_fatal(ssh, __func__, r);
(r = sshpkt_send(ssh)) != 0)
fatal("%s: %s", __func__, ssh_err(r)); if ((r = ssh_packet_write_wait(ssh)) != 0)
} else { sshpkt_fatal(ssh, __func__, r);
if ((r = sshpkt_start(ssh, SSH_MSG_DISCONNECT)) != 0 ||
(r = sshpkt_put_cstring(ssh, buf)) != 0 ||
(r = sshpkt_send(ssh)) != 0)
fatal("%s: %s", __func__, ssh_err(r));
}
ssh_packet_write_wait(ssh);
/* Close the connection. */ /* Close the connection. */
ssh_packet_close(ssh); ssh_packet_close(ssh);
cleanup_exit(255); cleanup_exit(255);
} }
/* Checks if there is any buffered output, and tries to write some of the output. */ /*
* Checks if there is any buffered output, and tries to write some of
void * the output.
*/
int
ssh_packet_write_poll(struct ssh *ssh) ssh_packet_write_poll(struct ssh *ssh)
{ {
struct session_state *state = ssh->state; struct session_state *state = ssh->state;
@ -1916,33 +1979,33 @@ ssh_packet_write_poll(struct ssh *ssh)
if (len == -1) { if (len == -1) {
if (errno == EINTR || errno == EAGAIN || if (errno == EINTR || errno == EAGAIN ||
errno == EWOULDBLOCK) errno == EWOULDBLOCK)
return; return 0;
fatal("Write failed: %.100s", strerror(errno)); return SSH_ERR_SYSTEM_ERROR;
} }
if (len == 0 && !cont) if (len == 0 && !cont)
fatal("Write connection closed"); return SSH_ERR_CONN_CLOSED;
if ((r = sshbuf_consume(state->output, len)) != 0) if ((r = sshbuf_consume(state->output, len)) != 0)
fatal("%s: %s", __func__, ssh_err(r)); return r;
} }
return 0;
} }
/* /*
* Calls packet_write_poll repeatedly until all pending output data has been * Calls packet_write_poll repeatedly until all pending output data has been
* written. * written.
*/ */
int
void
ssh_packet_write_wait(struct ssh *ssh) ssh_packet_write_wait(struct ssh *ssh)
{ {
fd_set *setp; fd_set *setp;
int ret, ms_remain = 0; int ret, r, ms_remain = 0;
struct timeval start, timeout, *timeoutp = NULL; struct timeval start, timeout, *timeoutp = NULL;
struct session_state *state = ssh->state; struct session_state *state = ssh->state;
setp = (fd_set *)calloc(howmany(state->connection_out + 1, setp = (fd_set *)calloc(howmany(state->connection_out + 1,
NFDBITS), sizeof(fd_mask)); NFDBITS), sizeof(fd_mask));
if (setp == NULL) if (setp == NULL)
fatal("%s: calloc failed", __func__); return SSH_ERR_ALLOC_FAIL;
ssh_packet_write_poll(ssh); ssh_packet_write_poll(ssh);
while (ssh_packet_have_data_to_write(ssh)) { while (ssh_packet_have_data_to_write(ssh)) {
memset(setp, 0, howmany(state->connection_out + 1, memset(setp, 0, howmany(state->connection_out + 1,
@ -1973,13 +2036,16 @@ ssh_packet_write_wait(struct ssh *ssh)
} }
} }
if (ret == 0) { if (ret == 0) {
logit("Connection to %.200s timed out while " free(setp);
"waiting to write", ssh_remote_ipaddr(ssh)); return SSH_ERR_CONN_TIMEOUT;
cleanup_exit(255); }
if ((r = ssh_packet_write_poll(ssh)) != 0) {
free(setp);
return r;
} }
ssh_packet_write_poll(ssh);
} }
free(setp); free(setp);
return 0;
} }
/* Returns true if there is buffered data to write to the connection. */ /* Returns true if there is buffered data to write to the connection. */

View File

@ -1,4 +1,4 @@
/* $OpenBSD: packet.h,v 1.65 2015/01/28 21:15:47 djm Exp $ */ /* $OpenBSD: packet.h,v 1.66 2015/01/30 01:13:33 djm Exp $ */
/* /*
* Author: Tatu Ylonen <ylo@cs.hut.fi> * Author: Tatu Ylonen <ylo@cs.hut.fi>
@ -90,7 +90,7 @@ int ssh_packet_send2_wrapped(struct ssh *);
int ssh_packet_send2(struct ssh *); int ssh_packet_send2(struct ssh *);
int ssh_packet_read(struct ssh *); int ssh_packet_read(struct ssh *);
void ssh_packet_read_expect(struct ssh *, int type); int ssh_packet_read_expect(struct ssh *, u_int type);
int ssh_packet_read_poll(struct ssh *); int ssh_packet_read_poll(struct ssh *);
int ssh_packet_read_poll1(struct ssh *, u_char *); int ssh_packet_read_poll1(struct ssh *, u_char *);
int ssh_packet_read_poll2(struct ssh *, u_char *, u_int32_t *seqnr_p); int ssh_packet_read_poll2(struct ssh *, u_char *, u_int32_t *seqnr_p);
@ -112,8 +112,8 @@ typedef void (ssh_packet_comp_free_func)(void *, void *);
void ssh_packet_set_compress_hooks(struct ssh *, void *, void ssh_packet_set_compress_hooks(struct ssh *, void *,
ssh_packet_comp_alloc_func *, ssh_packet_comp_free_func *); ssh_packet_comp_alloc_func *, ssh_packet_comp_free_func *);
void ssh_packet_write_poll(struct ssh *); int ssh_packet_write_poll(struct ssh *);
void ssh_packet_write_wait(struct ssh *); int ssh_packet_write_wait(struct ssh *);
int ssh_packet_have_data_to_write(struct ssh *); int ssh_packet_have_data_to_write(struct ssh *);
int ssh_packet_not_very_much_data_to_write(struct ssh *); int ssh_packet_not_very_much_data_to_write(struct ssh *);
@ -148,8 +148,10 @@ void *ssh_packet_get_output(struct ssh *);
/* new API */ /* new API */
int sshpkt_start(struct ssh *ssh, u_char type); int sshpkt_start(struct ssh *ssh, u_char type);
int sshpkt_send(struct ssh *ssh); int sshpkt_send(struct ssh *ssh);
int sshpkt_disconnect(struct ssh *, const char *fmt, ...) __attribute__((format(printf, 2, 3))); int sshpkt_disconnect(struct ssh *, const char *fmt, ...)
__attribute__((format(printf, 2, 3)));
int sshpkt_add_padding(struct ssh *, u_char); int sshpkt_add_padding(struct ssh *, u_char);
void sshpkt_fatal(struct ssh *ssh, const char *tag, int r);
int sshpkt_put(struct ssh *ssh, const void *v, size_t len); int sshpkt_put(struct ssh *ssh, const void *v, size_t len);
int sshpkt_putb(struct ssh *ssh, const struct sshbuf *b); int sshpkt_putb(struct ssh *ssh, const struct sshbuf *b);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: ssh-keyscan.c,v 1.97 2015/01/28 21:15:47 djm Exp $ */ /* $OpenBSD: ssh-keyscan.c,v 1.98 2015/01/30 01:13:33 djm Exp $ */
/* /*
* Copyright 1995, 1996 by David Mazieres <dm@lcs.mit.edu>. * Copyright 1995, 1996 by David Mazieres <dm@lcs.mit.edu>.
* *
@ -466,7 +466,8 @@ congreet(int s)
return; return;
} }
*cp = '\0'; *cp = '\0';
c->c_ssh = ssh_packet_set_connection(NULL, s, s); if ((c->c_ssh = ssh_packet_set_connection(NULL, s, s)) == NULL)
fatal("ssh_packet_set_connection failed");
ssh_set_app_data(c->c_ssh, c); /* back link */ ssh_set_app_data(c->c_ssh, c); /* back link */
if (sscanf(buf, "SSH-%d.%d-%[^\n]\n", if (sscanf(buf, "SSH-%d.%d-%[^\n]\n",
&remote_major, &remote_minor, remote_version) == 3) &remote_major, &remote_minor, remote_version) == 3)

View File

@ -1,4 +1,4 @@
/* $OpenBSD: ssh_api.c,v 1.2 2015/01/26 06:10:03 djm Exp $ */ /* $OpenBSD: ssh_api.c,v 1.3 2015/01/30 01:13:33 djm Exp $ */
/* /*
* Copyright (c) 2012 Markus Friedl. All rights reserved. * Copyright (c) 2012 Markus Friedl. All rights reserved.
* *
@ -85,7 +85,8 @@ ssh_init(struct ssh **sshp, int is_server, struct kex_params *kex_params)
called = 1; called = 1;
} }
ssh = ssh_packet_set_connection(NULL, -1, -1); if ((ssh = ssh_packet_set_connection(NULL, -1, -1)) == NULL)
return SSH_ERR_ALLOC_FAIL;
if (is_server) if (is_server)
ssh_packet_set_server(ssh); ssh_packet_set_server(ssh);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: ssherr.c,v 1.2 2015/01/28 21:15:47 djm Exp $ */ /* $OpenBSD: ssherr.c,v 1.3 2015/01/30 01:13:33 djm Exp $ */
/* /*
* Copyright (c) 2011 Damien Miller * Copyright (c) 2011 Damien Miller
* *
@ -129,6 +129,10 @@ ssh_err(int n)
return "Connection closed"; return "Connection closed";
case SSH_ERR_CONN_TIMEOUT: case SSH_ERR_CONN_TIMEOUT:
return "Connection timed out"; return "Connection timed out";
case SSH_ERR_CONN_CORRUPT:
return "Connection corrupted";
case SSH_ERR_PROTOCOL_ERROR:
return "Protocol error";
default: default:
return "unknown error"; return "unknown error";
} }

View File

@ -1,4 +1,4 @@
/* $OpenBSD: ssherr.h,v 1.2 2015/01/28 21:15:47 djm Exp $ */ /* $OpenBSD: ssherr.h,v 1.3 2015/01/30 01:13:33 djm Exp $ */
/* /*
* Copyright (c) 2011 Damien Miller * Copyright (c) 2011 Damien Miller
* *
@ -75,6 +75,8 @@
#define SSH_ERR_KEY_REVOKED -51 #define SSH_ERR_KEY_REVOKED -51
#define SSH_ERR_CONN_CLOSED -52 #define SSH_ERR_CONN_CLOSED -52
#define SSH_ERR_CONN_TIMEOUT -53 #define SSH_ERR_CONN_TIMEOUT -53
#define SSH_ERR_CONN_CORRUPT -54
#define SSH_ERR_PROTOCOL_ERROR -55
/* Translate a numeric error code to a human-readable error string */ /* Translate a numeric error code to a human-readable error string */
const char *ssh_err(int n); const char *ssh_err(int n);