version 1.309.4.1, 2023/12/18 14:57:43 |
version 1.310, 2023/04/06 03:21:31 |
|
|
sshbuf_dump(state->output, stderr); |
sshbuf_dump(state->output, stderr); |
#endif |
#endif |
/* increment sequence number for outgoing packets */ |
/* increment sequence number for outgoing packets */ |
if (++state->p_send.seqnr == 0) { |
if (++state->p_send.seqnr == 0) |
if ((ssh->kex->flags & KEX_INITIAL) != 0) { |
|
ssh_packet_disconnect(ssh, "outgoing sequence number " |
|
"wrapped during initial key exchange"); |
|
} |
|
logit("outgoing seqnr wraps around"); |
logit("outgoing seqnr wraps around"); |
} |
|
if (++state->p_send.packets == 0) |
if (++state->p_send.packets == 0) |
if (!(ssh->compat & SSH_BUG_NOREKEY)) |
if (!(ssh->compat & SSH_BUG_NOREKEY)) |
return SSH_ERR_NEED_REKEY; |
return SSH_ERR_NEED_REKEY; |
|
|
state->p_send.bytes += len; |
state->p_send.bytes += len; |
sshbuf_reset(state->outgoing_packet); |
sshbuf_reset(state->outgoing_packet); |
|
|
if (type == SSH2_MSG_NEWKEYS && ssh->kex->kex_strict) { |
|
debug_f("resetting send seqnr %u", state->p_send.seqnr); |
|
state->p_send.seqnr = 0; |
|
} |
|
|
|
if (type == SSH2_MSG_NEWKEYS) |
if (type == SSH2_MSG_NEWKEYS) |
r = ssh_set_newkeys(ssh, MODE_OUT); |
r = ssh_set_newkeys(ssh, MODE_OUT); |
else if (type == SSH2_MSG_USERAUTH_SUCCESS && state->server_side) |
else if (type == SSH2_MSG_USERAUTH_SUCCESS && state->server_side) |
|
|
/* Stay in the loop until we have received a complete packet. */ |
/* Stay in the loop until we have received a complete packet. */ |
for (;;) { |
for (;;) { |
/* Try to read a packet from the buffer. */ |
/* Try to read a packet from the buffer. */ |
if ((r = ssh_packet_read_poll_seqnr(ssh, typep, seqnr_p)) != 0) |
r = ssh_packet_read_poll_seqnr(ssh, typep, seqnr_p); |
|
if (r != 0) |
break; |
break; |
/* If we got a packet, return it. */ |
/* If we got a packet, return it. */ |
if (*typep != SSH_MSG_NONE) |
if (*typep != SSH_MSG_NONE) |
|
|
return type; |
return type; |
} |
} |
|
|
|
/* |
|
* Waits until a packet has been received, verifies that its type matches |
|
* that given, and gives a fatal error and exits if there is a mismatch. |
|
*/ |
|
|
|
int |
|
ssh_packet_read_expect(struct ssh *ssh, u_int expected_type) |
|
{ |
|
int r; |
|
u_char type; |
|
|
|
if ((r = ssh_packet_read_seqnr(ssh, &type, NULL)) != 0) |
|
return r; |
|
if (type != expected_type) { |
|
if ((r = sshpkt_disconnect(ssh, |
|
"Protocol error: expected packet type %d, got %d", |
|
expected_type, type)) != 0) |
|
return r; |
|
return SSH_ERR_PROTOCOL_ERROR; |
|
} |
|
return 0; |
|
} |
|
|
static int |
static int |
ssh_packet_read_poll2_mux(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p) |
ssh_packet_read_poll2_mux(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; |
} |
} |
|
|
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) |
if ((ssh->kex->flags & KEX_INITIAL) != 0) { |
|
ssh_packet_disconnect(ssh, "incoming sequence number " |
|
"wrapped during initial key exchange"); |
|
} |
|
logit("incoming seqnr wraps around"); |
logit("incoming seqnr wraps around"); |
} |
|
if (++state->p_read.packets == 0) |
if (++state->p_read.packets == 0) |
if (!(ssh->compat & SSH_BUG_NOREKEY)) |
if (!(ssh->compat & SSH_BUG_NOREKEY)) |
return SSH_ERR_NEED_REKEY; |
return SSH_ERR_NEED_REKEY; |
|
|
#endif |
#endif |
/* reset for next packet */ |
/* reset for next packet */ |
state->packlen = 0; |
state->packlen = 0; |
if (*typep == SSH2_MSG_NEWKEYS && ssh->kex->kex_strict) { |
|
debug_f("resetting read seqnr %u", state->p_read.seqnr); |
|
state->p_read.seqnr = 0; |
|
} |
|
|
|
if ((r = ssh_packet_check_rekey(ssh)) != 0) |
if ((r = ssh_packet_check_rekey(ssh)) != 0) |
return r; |
return r; |
|
|
r = ssh_packet_read_poll2(ssh, typep, seqnr_p); |
r = ssh_packet_read_poll2(ssh, typep, seqnr_p); |
if (r != 0) |
if (r != 0) |
return r; |
return r; |
if (*typep == 0) { |
if (*typep) { |
/* no message ready */ |
state->keep_alive_timeouts = 0; |
return 0; |
DBG(debug("received packet type %d", *typep)); |
} |
} |
state->keep_alive_timeouts = 0; |
|
DBG(debug("received packet type %d", *typep)); |
|
|
|
/* Always process disconnect messages */ |
|
if (*typep == 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; |
|
} |
|
|
|
/* |
|
* Do not implicitly handle any messages here during initial |
|
* KEX when in strict mode. They will be need to be allowed |
|
* explicitly by the KEX dispatch table or they will generate |
|
* protocol errors. |
|
*/ |
|
if (ssh->kex != NULL && |
|
(ssh->kex->flags & KEX_INITIAL) && ssh->kex->kex_strict) |
|
return 0; |
|
/* Implicitly handle transport-level messages */ |
|
switch (*typep) { |
switch (*typep) { |
case SSH2_MSG_IGNORE: |
case SSH2_MSG_IGNORE: |
debug3("Received SSH2_MSG_IGNORE"); |
debug3("Received SSH2_MSG_IGNORE"); |
|
|
debug("Remote: %.900s", msg); |
debug("Remote: %.900s", msg); |
free(msg); |
free(msg); |
break; |
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: |
case SSH2_MSG_UNIMPLEMENTED: |
if ((r = sshpkt_get_u32(ssh, &seqnr)) != 0) |
if ((r = sshpkt_get_u32(ssh, &seqnr)) != 0) |
return r; |
return r; |
|
|
case SSH_ERR_NO_COMPRESS_ALG_MATCH: |
case SSH_ERR_NO_COMPRESS_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->kex && ssh->kex->failed_choice) { |
ssh_packet_clear_keys(ssh); |
ssh_packet_clear_keys(ssh); |
errno = oerrno; |
errno = oerrno; |
logdie("Unable to negotiate with %s: %s. " |
logdie("Unable to negotiate with %s: %s. " |
|
|
(r = sshbuf_put_u32(m, kex->hostkey_type)) != 0 || |
(r = sshbuf_put_u32(m, kex->hostkey_type)) != 0 || |
(r = sshbuf_put_u32(m, kex->hostkey_nid)) != 0 || |
(r = sshbuf_put_u32(m, kex->hostkey_nid)) != 0 || |
(r = sshbuf_put_u32(m, kex->kex_type)) != 0 || |
(r = sshbuf_put_u32(m, kex->kex_type)) != 0 || |
(r = sshbuf_put_u32(m, kex->kex_strict)) != 0 || |
|
(r = sshbuf_put_stringb(m, kex->my)) != 0 || |
(r = sshbuf_put_stringb(m, kex->my)) != 0 || |
(r = sshbuf_put_stringb(m, kex->peer)) != 0 || |
(r = sshbuf_put_stringb(m, kex->peer)) != 0 || |
(r = sshbuf_put_stringb(m, kex->client_version)) != 0 || |
(r = sshbuf_put_stringb(m, kex->client_version)) != 0 || |
|
|
(r = sshbuf_get_u32(m, (u_int *)&kex->hostkey_type)) != 0 || |
(r = sshbuf_get_u32(m, (u_int *)&kex->hostkey_type)) != 0 || |
(r = sshbuf_get_u32(m, (u_int *)&kex->hostkey_nid)) != 0 || |
(r = sshbuf_get_u32(m, (u_int *)&kex->hostkey_nid)) != 0 || |
(r = sshbuf_get_u32(m, &kex->kex_type)) != 0 || |
(r = sshbuf_get_u32(m, &kex->kex_type)) != 0 || |
(r = sshbuf_get_u32(m, &kex->kex_strict)) != 0 || |
|
(r = sshbuf_get_stringb(m, kex->my)) != 0 || |
(r = sshbuf_get_stringb(m, kex->my)) != 0 || |
(r = sshbuf_get_stringb(m, kex->peer)) != 0 || |
(r = sshbuf_get_stringb(m, kex->peer)) != 0 || |
(r = sshbuf_get_stringb(m, kex->client_version)) != 0 || |
(r = sshbuf_get_stringb(m, kex->client_version)) != 0 || |
|
|
vsnprintf(buf, sizeof(buf), fmt, args); |
vsnprintf(buf, sizeof(buf), fmt, args); |
va_end(args); |
va_end(args); |
|
|
debug2_f("sending SSH2_MSG_DISCONNECT: %s", buf); |
|
if ((r = sshpkt_start(ssh, SSH2_MSG_DISCONNECT)) != 0 || |
if ((r = sshpkt_start(ssh, SSH2_MSG_DISCONNECT)) != 0 || |
(r = sshpkt_put_u32(ssh, SSH2_DISCONNECT_PROTOCOL_ERROR)) != 0 || |
(r = sshpkt_put_u32(ssh, SSH2_DISCONNECT_PROTOCOL_ERROR)) != 0 || |
(r = sshpkt_put_cstring(ssh, buf)) != 0 || |
(r = sshpkt_put_cstring(ssh, buf)) != 0 || |