version 1.256, 2017/05/08 06:03:39 |
version 1.257, 2017/05/31 08:09:45 |
|
|
|
|
/* Closes the connection and clears and frees internal data structures. */ |
/* Closes the connection and clears and frees internal data structures. */ |
|
|
void |
static void |
ssh_packet_close(struct ssh *ssh) |
ssh_packet_close_internal(struct ssh *ssh, int do_close) |
{ |
{ |
struct session_state *state = ssh->state; |
struct session_state *state = ssh->state; |
u_int mode; |
u_int mode; |
|
|
if (!state->initialized) |
if (!state->initialized) |
return; |
return; |
state->initialized = 0; |
state->initialized = 0; |
if (state->connection_in == state->connection_out) { |
if (do_close) { |
shutdown(state->connection_out, SHUT_RDWR); |
if (state->connection_in == state->connection_out) { |
close(state->connection_out); |
shutdown(state->connection_out, SHUT_RDWR); |
} else { |
close(state->connection_out); |
close(state->connection_in); |
} else { |
close(state->connection_out); |
close(state->connection_in); |
|
close(state->connection_out); |
|
} |
} |
} |
sshbuf_free(state->input); |
sshbuf_free(state->input); |
sshbuf_free(state->output); |
sshbuf_free(state->output); |
sshbuf_free(state->outgoing_packet); |
sshbuf_free(state->outgoing_packet); |
sshbuf_free(state->incoming_packet); |
sshbuf_free(state->incoming_packet); |
for (mode = 0; mode < MODE_MAX; mode++) |
for (mode = 0; mode < MODE_MAX; mode++) { |
kex_free_newkeys(state->newkeys[mode]); |
kex_free_newkeys(state->newkeys[mode]); /* current keys */ |
if (state->compression_buffer) { |
state->newkeys[mode] = NULL; |
|
ssh_clear_newkeys(ssh, mode); /* next keys */ |
|
} |
|
/* comression state is in shared mem, so we can only release it once */ |
|
if (do_close && state->compression_buffer) { |
sshbuf_free(state->compression_buffer); |
sshbuf_free(state->compression_buffer); |
if (state->compression_out_started) { |
if (state->compression_out_started) { |
z_streamp stream = &state->compression_out_stream; |
z_streamp stream = &state->compression_out_stream; |
|
|
cipher_free(state->send_context); |
cipher_free(state->send_context); |
cipher_free(state->receive_context); |
cipher_free(state->receive_context); |
state->send_context = state->receive_context = NULL; |
state->send_context = state->receive_context = NULL; |
free(ssh->remote_ipaddr); |
if (do_close) { |
ssh->remote_ipaddr = NULL; |
free(ssh->remote_ipaddr); |
free(ssh->state); |
ssh->remote_ipaddr = NULL; |
ssh->state = NULL; |
free(ssh->state); |
|
ssh->state = NULL; |
|
} |
} |
} |
|
|
|
void |
|
ssh_packet_close(struct ssh *ssh) |
|
{ |
|
ssh_packet_close_internal(ssh, 1); |
|
} |
|
|
|
void |
|
ssh_packet_clear_keys(struct ssh *ssh) |
|
{ |
|
ssh_packet_close_internal(ssh, 0); |
|
} |
|
|
/* Sets remote side protocol flags. */ |
/* Sets remote side protocol flags. */ |
|
|
void |
void |
|
|
/* NOTREACHED */ |
/* NOTREACHED */ |
} |
} |
|
|
|
void |
|
ssh_clear_newkeys(struct ssh *ssh, int mode) |
|
{ |
|
if (ssh->kex && ssh->kex->newkeys) { |
|
kex_free_newkeys(ssh->kex->newkeys[mode]); |
|
ssh->kex->newkeys[mode] = NULL; |
|
} |
|
} |
|
|
int |
int |
ssh_set_newkeys(struct ssh *ssh, int mode) |
ssh_set_newkeys(struct ssh *ssh, int mode) |
{ |
{ |
|
|
max_blocks = &state->max_blocks_in; |
max_blocks = &state->max_blocks_in; |
} |
} |
if (state->newkeys[mode] != NULL) { |
if (state->newkeys[mode] != NULL) { |
debug("%s: rekeying after %llu %s blocks" |
debug("set_newkeys: rekeying, input %llu bytes %llu blocks, " |
" (%llu bytes total)", __func__, |
"output %llu bytes %llu blocks", |
(unsigned long long)ps->blocks, dir, |
(unsigned long long)state->p_read.bytes, |
(unsigned long long)ps->bytes); |
(unsigned long long)state->p_read.blocks, |
|
(unsigned long long)state->p_send.bytes, |
|
(unsigned long long)state->p_send.blocks); |
cipher_free(*ccp); |
cipher_free(*ccp); |
*ccp = NULL; |
*ccp = NULL; |
enc = &state->newkeys[mode]->enc; |
kex_free_newkeys(state->newkeys[mode]); |
mac = &state->newkeys[mode]->mac; |
state->newkeys[mode] = NULL; |
comp = &state->newkeys[mode]->comp; |
|
mac_clear(mac); |
|
explicit_bzero(enc->iv, enc->iv_len); |
|
explicit_bzero(enc->key, enc->key_len); |
|
explicit_bzero(mac->key, mac->key_len); |
|
free(enc->name); |
|
free(enc->iv); |
|
free(enc->key); |
|
free(mac->name); |
|
free(mac->key); |
|
free(comp->name); |
|
free(state->newkeys[mode]); |
|
} |
} |
/* note that both bytes and the seqnr are not reset */ |
/* note that both bytes and the seqnr are not reset */ |
ps->packets = ps->blocks = 0; |
ps->packets = ps->blocks = 0; |
|
|
|
|
switch (r) { |
switch (r) { |
case SSH_ERR_CONN_CLOSED: |
case SSH_ERR_CONN_CLOSED: |
|
ssh_packet_clear_keys(ssh); |
logdie("Connection closed by %s", remote_id); |
logdie("Connection closed by %s", remote_id); |
case SSH_ERR_CONN_TIMEOUT: |
case SSH_ERR_CONN_TIMEOUT: |
|
ssh_packet_clear_keys(ssh); |
logdie("Connection %s %s timed out", |
logdie("Connection %s %s timed out", |
ssh->state->server_side ? "from" : "to", remote_id); |
ssh->state->server_side ? "from" : "to", remote_id); |
case SSH_ERR_DISCONNECTED: |
case SSH_ERR_DISCONNECTED: |
|
ssh_packet_clear_keys(ssh); |
logdie("Disconnected from %s", remote_id); |
logdie("Disconnected from %s", remote_id); |
case SSH_ERR_SYSTEM_ERROR: |
case SSH_ERR_SYSTEM_ERROR: |
if (errno == ECONNRESET) |
if (errno == ECONNRESET) { |
|
ssh_packet_clear_keys(ssh); |
logdie("Connection reset by %s", remote_id); |
logdie("Connection reset by %s", remote_id); |
|
} |
/* FALLTHROUGH */ |
/* FALLTHROUGH */ |
case SSH_ERR_NO_CIPHER_ALG_MATCH: |
case SSH_ERR_NO_CIPHER_ALG_MATCH: |
case SSH_ERR_NO_MAC_ALG_MATCH: |
case SSH_ERR_NO_MAC_ALG_MATCH: |
|
|
case SSH_ERR_NO_KEX_ALG_MATCH: |
case SSH_ERR_NO_KEX_ALG_MATCH: |
case SSH_ERR_NO_HOSTKEY_ALG_MATCH: |
case SSH_ERR_NO_HOSTKEY_ALG_MATCH: |
if (ssh && ssh->kex && ssh->kex->failed_choice) { |
if (ssh && ssh->kex && ssh->kex->failed_choice) { |
|
ssh_packet_clear_keys(ssh); |
logdie("Unable to negotiate with %s: %s. " |
logdie("Unable to negotiate with %s: %s. " |
"Their offer: %s", remote_id, ssh_err(r), |
"Their offer: %s", remote_id, ssh_err(r), |
ssh->kex->failed_choice); |
ssh->kex->failed_choice); |
} |
} |
/* FALLTHROUGH */ |
/* FALLTHROUGH */ |
default: |
default: |
|
ssh_packet_clear_keys(ssh); |
logdie("%s%sConnection %s %s: %s", |
logdie("%s%sConnection %s %s: %s", |
tag != NULL ? tag : "", tag != NULL ? ": " : "", |
tag != NULL ? tag : "", tag != NULL ? ": " : "", |
ssh->state->server_side ? "from" : "to", |
ssh->state->server_side ? "from" : "to", |