| 726 |
* 'len' is the length of the * payload + padding (+ length of CRC for SSHv1). |
* 'len' is the length of the * payload + padding (+ length of CRC for SSHv1). |
| 727 |
* 'padding' is the length of the padding alone. |
* 'padding' is the length of the padding alone. |
| 728 |
*/ |
*/ |
| 729 |
static int prep_packet(PTInstVar pvar, char *data, int len, int padding) |
static int prep_packet_ssh1(PTInstVar pvar, char *data, int len, int padding) |
| 730 |
{ |
{ |
| 731 |
pvar->ssh_state.payload = data + 4; |
pvar->ssh_state.payload = data + 4; |
| 732 |
pvar->ssh_state.payloadlen = len; |
pvar->ssh_state.payloadlen = len; |
| 733 |
|
|
| 734 |
if (SSHv1(pvar)) { |
if (CRYPT_detect_attack(pvar, pvar->ssh_state.payload, len)) { |
| 735 |
if (CRYPT_detect_attack(pvar, pvar->ssh_state.payload, len)) { |
UTIL_get_lang_msg("MSG_SSH_COREINS_ERROR", pvar, "'CORE insertion attack' detected. Aborting connection."); |
| 736 |
UTIL_get_lang_msg("MSG_SSH_COREINS_ERROR", pvar, "'CORE insertion attack' detected. Aborting connection."); |
notify_fatal_error(pvar, pvar->ts->UIMsg, TRUE); |
| 737 |
notify_fatal_error(pvar, pvar->ts->UIMsg, TRUE); |
} |
|
} |
|
| 738 |
|
|
| 739 |
CRYPT_decrypt(pvar, pvar->ssh_state.payload, len); |
CRYPT_decrypt(pvar, pvar->ssh_state.payload, len); |
| 740 |
/* PKT guarantees that the data is always 4-byte aligned */ |
/* PKT guarantees that the data is always 4-byte aligned */ |
| 741 |
if (do_crc(pvar->ssh_state.payload, len - 4) != get_uint32_MSBfirst(pvar->ssh_state.payload + len - 4)) { |
if (do_crc(pvar->ssh_state.payload, len - 4) != get_uint32_MSBfirst(pvar->ssh_state.payload + len - 4)) { |
| 742 |
UTIL_get_lang_msg("MSG_SSH_CORRUPTDATA_ERROR", pvar, "Detected corrupted data; connection terminating."); |
UTIL_get_lang_msg("MSG_SSH_CORRUPTDATA_ERROR", pvar, "Detected corrupted data; connection terminating."); |
| 743 |
notify_fatal_error(pvar, pvar->ts->UIMsg, TRUE); |
notify_fatal_error(pvar, pvar->ts->UIMsg, TRUE); |
| 744 |
return SSH_MSG_NONE; |
return SSH_MSG_NONE; |
| 745 |
} |
} |
| 746 |
|
|
| 747 |
pvar->ssh_state.payload += padding; |
pvar->ssh_state.payload += padding; |
| 748 |
pvar->ssh_state.payloadlen -= padding + 4; |
pvar->ssh_state.payloadlen -= padding + 4; |
|
} else { |
|
|
int already_decrypted = get_predecryption_amount(pvar); |
|
| 749 |
|
|
| 750 |
CRYPT_decrypt(pvar, data + already_decrypted, (4 + len) - already_decrypted); |
pvar->ssh_state.payload_grabbed = 0; |
| 751 |
|
|
| 752 |
if (!CRYPT_verify_receiver_MAC(pvar, pvar->ssh_state.receiver_sequence_number, data, len + 4, data + len + 4)) { |
if (pvar->ssh_state.decompressing) { |
| 753 |
UTIL_get_lang_msg("MSG_SSH_CORRUPTDATA_ERROR", pvar, |
if (pvar->ssh_state.decompress_stream.avail_in != 0) { |
| 754 |
"Detected corrupted data; connection terminating."); |
UTIL_get_lang_msg("MSG_SSH_DECOMPRESS_ERROR", pvar, |
| 755 |
notify_fatal_error(pvar, pvar->ts->UIMsg, TRUE); |
"Internal error: a packet was not fully decompressed.\n" |
| 756 |
return SSH_MSG_NONE; |
"This is a bug, please report it."); |
| 757 |
|
notify_nonfatal_error(pvar, pvar->ts->UIMsg); |
| 758 |
} |
} |
| 759 |
|
|
| 760 |
|
pvar->ssh_state.decompress_stream.next_in = pvar->ssh_state.payload; |
| 761 |
|
pvar->ssh_state.decompress_stream.avail_in = pvar->ssh_state.payloadlen; |
| 762 |
|
pvar->ssh_state.decompress_stream.next_out = pvar->ssh_state.postdecompress_inbuf; |
| 763 |
|
pvar->ssh_state.payloadlen = -1; |
| 764 |
|
} else { |
| 765 |
pvar->ssh_state.payload++; |
pvar->ssh_state.payload++; |
|
pvar->ssh_state.payloadlen -= padding + 1; |
|
| 766 |
} |
} |
| 767 |
|
|
| 768 |
pvar->ssh_state.payload_grabbed = 0; |
if (!grab_payload_limited(pvar, 1)) { |
| 769 |
|
return SSH_MSG_NONE; |
| 770 |
|
} |
| 771 |
|
|
| 772 |
if (SSHv1(pvar)) { |
pvar->ssh_state.receiver_sequence_number++; |
|
if (pvar->ssh_state.decompressing) { |
|
|
if (pvar->ssh_state.decompress_stream.avail_in != 0) { |
|
|
UTIL_get_lang_msg("MSG_SSH_DECOMPRESS_ERROR", pvar, |
|
|
"Internal error: a packet was not fully decompressed.\n" |
|
|
"This is a bug, please report it."); |
|
|
notify_nonfatal_error(pvar, pvar->ts->UIMsg); |
|
|
} |
|
| 773 |
|
|
| 774 |
pvar->ssh_state.decompress_stream.next_in = pvar->ssh_state.payload; |
return pvar->ssh_state.payload[-1]; |
| 775 |
pvar->ssh_state.decompress_stream.avail_in = pvar->ssh_state.payloadlen; |
} |
|
pvar->ssh_state.decompress_stream.next_out = pvar->ssh_state.postdecompress_inbuf; |
|
|
pvar->ssh_state.payloadlen = -1; |
|
|
} else { |
|
|
pvar->ssh_state.payload++; |
|
|
} |
|
| 776 |
|
|
| 777 |
if (!grab_payload_limited(pvar, 1)) { |
static int prep_packet_ssh2(PTInstVar pvar, char *data, int len, int padding) |
| 778 |
return SSH_MSG_NONE; |
{ |
| 779 |
} |
int already_decrypted = get_predecryption_amount(pvar); |
| 780 |
|
|
| 781 |
} else { |
pvar->ssh_state.payload = data + 4; |
| 782 |
// support of SSH2 packet compression (2005.7.9 yutaka) |
pvar->ssh_state.payloadlen = len; |
|
// support of "Compression delayed" (2006.6.23 maya) |
|
|
if ((pvar->stoc_compression == COMP_ZLIB || |
|
|
pvar->stoc_compression == COMP_DELAYED && pvar->userauth_success) && |
|
|
pvar->ssh2_keys[MODE_IN].comp.enabled) { // compression enabled |
|
|
int ret; |
|
|
|
|
|
if (pvar->decomp_buffer == NULL) { |
|
|
pvar->decomp_buffer = buffer_init(); |
|
|
if (pvar->decomp_buffer == NULL) |
|
|
return SSH_MSG_NONE; |
|
|
} |
|
|
// 一度確保したバッファは使い回すので初期化を忘れずに。 |
|
|
buffer_clear(pvar->decomp_buffer); |
|
| 783 |
|
|
| 784 |
// packet sizeとpaddingを取り除いたペイロード部分のみを展開する。 |
CRYPT_decrypt(pvar, data + already_decrypted, (4 + len) - already_decrypted); |
|
ret = buffer_decompress(&pvar->ssh_state.decompress_stream, |
|
|
pvar->ssh_state.payload, |
|
|
pvar->ssh_state.payloadlen, |
|
|
pvar->decomp_buffer); |
|
|
|
|
|
// ポインタの更新。 |
|
|
pvar->ssh_state.payload = buffer_ptr(pvar->decomp_buffer); |
|
|
pvar->ssh_state.payload++; |
|
|
pvar->ssh_state.payloadlen = buffer_len(pvar->decomp_buffer); |
|
| 785 |
|
|
| 786 |
} else { |
if (!CRYPT_verify_receiver_MAC(pvar, pvar->ssh_state.receiver_sequence_number, data, len + 4, data + len + 4)) { |
| 787 |
pvar->ssh_state.payload++; |
UTIL_get_lang_msg("MSG_SSH_CORRUPTDATA_ERROR", pvar, "Detected corrupted data; connection terminating."); |
| 788 |
} |
notify_fatal_error(pvar, pvar->ts->UIMsg, TRUE); |
| 789 |
|
return SSH_MSG_NONE; |
| 790 |
|
} |
| 791 |
|
|
| 792 |
if (!grab_payload_limited(pvar, 1)) { |
pvar->ssh_state.payload++; |
| 793 |
return SSH_MSG_NONE; |
pvar->ssh_state.payloadlen -= padding + 1; |
|
} |
|
| 794 |
|
|
| 795 |
|
pvar->ssh_state.payload_grabbed = 0; |
| 796 |
|
|
| 797 |
|
// data compression |
| 798 |
|
if (pvar->ssh2_keys[MODE_IN].comp.enabled && |
| 799 |
|
(pvar->stoc_compression == COMP_ZLIB || |
| 800 |
|
pvar->stoc_compression == COMP_DELAYED && pvar->userauth_success)) { |
| 801 |
|
|
| 802 |
|
if (pvar->decomp_buffer == NULL) { |
| 803 |
|
pvar->decomp_buffer = buffer_init(); |
| 804 |
|
if (pvar->decomp_buffer == NULL) |
| 805 |
|
return SSH_MSG_NONE; |
| 806 |
|
} |
| 807 |
|
// 一度確保したバッファは使い回すので初期化を忘れずに。 |
| 808 |
|
buffer_clear(pvar->decomp_buffer); |
| 809 |
|
|
| 810 |
|
// packet sizeとpaddingを取り除いたペイロード部分のみを展開する。 |
| 811 |
|
buffer_decompress(&pvar->ssh_state.decompress_stream, |
| 812 |
|
pvar->ssh_state.payload, |
| 813 |
|
pvar->ssh_state.payloadlen, |
| 814 |
|
pvar->decomp_buffer); |
| 815 |
|
|
| 816 |
|
// ポインタの更新。 |
| 817 |
|
pvar->ssh_state.payload = buffer_ptr(pvar->decomp_buffer); |
| 818 |
|
pvar->ssh_state.payload++; |
| 819 |
|
pvar->ssh_state.payloadlen = buffer_len(pvar->decomp_buffer); |
| 820 |
|
} else { |
| 821 |
|
pvar->ssh_state.payload++; |
| 822 |
|
} |
| 823 |
|
|
| 824 |
|
if (!grab_payload_limited(pvar, 1)) { |
| 825 |
|
return SSH_MSG_NONE; |
| 826 |
} |
} |
| 827 |
|
|
| 828 |
pvar->ssh_state.receiver_sequence_number++; |
pvar->ssh_state.receiver_sequence_number++; |
| 2036 |
} |
} |
| 2037 |
|
|
| 2038 |
|
|
| 2039 |
void SSH_handle_packet(PTInstVar pvar, char *data, int len, int padding) |
void SSH_handle_packet1(PTInstVar pvar, char *data, int len, int padding) |
| 2040 |
{ |
{ |
| 2041 |
unsigned char message = prep_packet(pvar, data, len, padding); |
unsigned char message = prep_packet_ssh1(pvar, data, len, padding); |
| 2042 |
|
|
| 2043 |
// SSHのメッセージタイプをチェック |
// SSHのメッセージタイプをチェック |
| 2044 |
if (message != SSH_MSG_NONE) { |
if (message != SSH_MSG_NONE) { |
| 2045 |
// メッセージタイプに応じたハンドラを起動 |
// メッセージタイプに応じたハンドラを起動 |
| 2046 |
SSHPacketHandler handler = get_handler(pvar, message); |
SSHPacketHandler handler = get_handler(pvar, message); |
| 2047 |
|
|
| 2048 |
// for SSH2(yutaka) |
if (handler == NULL) { |
| 2049 |
if (SSHv2(pvar)) { |
char buf[1024]; |
| 2050 |
// 想定外のメッセージタイプが到着したらアボートさせる。 |
|
| 2051 |
if (!SSH2_dispatch_enabled_check(message) || handler == NULL) { |
UTIL_get_lang_msg("MSG_SSH_UNEXP_MSG_ERROR", pvar, "Unexpected packet type received: %d"); |
| 2052 |
char buf[1024]; |
_snprintf_s(buf, sizeof(buf), _TRUNCATE, pvar->ts->UIMsg, message, handle_message_stage); |
| 2053 |
|
notify_fatal_error(pvar, buf, TRUE); |
| 2054 |
UTIL_get_lang_msg("MSG_SSH_UNEXP_MSG2_ERROR", pvar, "Unexpected SSH2 message(%d) on current stage(%d)"); |
} else { |
| 2055 |
_snprintf_s(buf, sizeof(buf), _TRUNCATE, pvar->ts->UIMsg, message, handle_message_stage); |
if (!handler(pvar)) { |
| 2056 |
notify_fatal_error(pvar, buf, TRUE); |
deque_handlers(pvar, message); |
|
return; |
|
| 2057 |
} |
} |
| 2058 |
} |
} |
| 2059 |
|
} |
| 2060 |
|
} |
| 2061 |
|
|
| 2062 |
|
void SSH_handle_packet2(PTInstVar pvar, char *data, int len, int padding) |
| 2063 |
|
{ |
| 2064 |
|
unsigned char message = prep_packet_ssh2(pvar, data, len, padding); |
| 2065 |
|
|
| 2066 |
|
// SSHのメッセージタイプをチェック |
| 2067 |
|
if (message != SSH_MSG_NONE) { |
| 2068 |
|
// メッセージタイプに応じたハンドラを起動 |
| 2069 |
|
SSHPacketHandler handler = get_handler(pvar, message); |
| 2070 |
|
|
| 2071 |
|
// 想定外のメッセージタイプが到着したらアボートさせる。 |
| 2072 |
|
if (!SSH2_dispatch_enabled_check(message) || handler == NULL) { |
| 2073 |
|
char buf[1024]; |
| 2074 |
|
|
| 2075 |
|
UTIL_get_lang_msg("MSG_SSH_UNEXP_MSG2_ERROR", pvar, "Unexpected SSH2 message(%d) on current stage(%d)"); |
| 2076 |
|
_snprintf_s(buf, sizeof(buf), _TRUNCATE, pvar->ts->UIMsg, message, handle_message_stage); |
| 2077 |
|
notify_fatal_error(pvar, buf, TRUE); |
| 2078 |
|
return; |
| 2079 |
|
} |
| 2080 |
|
|
| 2081 |
if (handler == NULL) { |
if (handler == NULL) { |
| 2082 |
if (SSHv1(pvar)) { |
unsigned char *outmsg = begin_send_packet(pvar, SSH2_MSG_UNIMPLEMENTED, 4); |
|
char buf[1024]; |
|
| 2083 |
|
|
| 2084 |
UTIL_get_lang_msg("MSG_SSH_UNEXP_MSG_ERROR", pvar, "Unexpected packet type received: %d"); |
set_uint32(outmsg, pvar->ssh_state.receiver_sequence_number - 1); |
| 2085 |
_snprintf_s(buf, sizeof(buf), _TRUNCATE, pvar->ts->UIMsg, message, handle_message_stage); |
finish_send_packet(pvar); |
|
notify_fatal_error(pvar, buf, TRUE); |
|
|
} else { |
|
|
unsigned char *outmsg = begin_send_packet(pvar, SSH2_MSG_UNIMPLEMENTED, 4); |
|
|
|
|
|
set_uint32(outmsg, pvar->ssh_state.receiver_sequence_number - 1); |
|
|
finish_send_packet(pvar); |
|
| 2086 |
|
|
| 2087 |
logputs(LOG_LEVEL_VERBOSE, "SSH2_MSG_UNIMPLEMENTED was sent at SSH_handle_packet()."); |
logputs(LOG_LEVEL_VERBOSE, __FUNCTION__ ": SSH2_MSG_UNIMPLEMENTED was sent."); |
| 2088 |
/* XXX need to decompress incoming packet, but how? */ |
/* XXX need to decompress incoming packet, but how? */ |
|
} |
|
| 2089 |
} else { |
} else { |
| 2090 |
if (!handler(pvar)) { |
if (!handler(pvar)) { |
| 2091 |
deque_handlers(pvar, message); |
deque_handlers(pvar, message); |