diff options
-rw-r--r-- | include/libssh/packet.h | 6 | ||||
-rw-r--r-- | src/packet.c | 787 |
2 files changed, 791 insertions, 2 deletions
diff --git a/include/libssh/packet.h b/include/libssh/packet.h index d8ef35bb..206c0b21 100644 --- a/include/libssh/packet.h +++ b/include/libssh/packet.h @@ -43,6 +43,12 @@ enum ssh_packet_state_e { PACKET_STATE_PROCESSING }; +enum ssh_packet_filter_result_e { + SSH_PACKET_UNKNOWN, + SSH_PACKET_ALLOWED, + SSH_PACKET_DENIED +}; + int packet_send(ssh_session session); #ifdef WITH_SSH1 diff --git a/src/packet.c b/src/packet.c index d16cd165..5a263328 100644 --- a/src/packet.c +++ b/src/packet.c @@ -127,6 +127,775 @@ static ssh_packet_callback default_packet_handlers[]= { ssh_packet_channel_failure, // SSH2_MSG_CHANNEL_FAILURE 100 }; +/** @internal + * @brief check if the received packet is allowed for the current session state + * @param session current ssh_session + * @returns SSH_PACKET_ALLOWED if the packet is allowed; SSH_PACKET_DENIED + * if the packet arrived in wrong state; SSH_PACKET_UNKNOWN if the packet type + * is unknown + */ +static enum ssh_packet_filter_result_e ssh_packet_incoming_filter(ssh_session session) +{ + enum ssh_packet_filter_result_e rc; + +#ifdef DEBUG_PACKET + SSH_LOG(SSH_LOG_PACKET, "Filtering packet type %d", + session->in_packet.type); +#endif + + switch(session->in_packet.type) { + case SSH2_MSG_DISCONNECT: // 1 + /* + * States required: + * - None + * + * Transitions: + * - session->socket->state = SSH_SOCKET_CLOSED + * - session->session_state = SSH_SESSION_STATE_ERROR + * */ + + /* Always allowed */ + rc = SSH_PACKET_ALLOWED; + break; + case SSH2_MSG_IGNORE: // 2 + /* + * States required: + * - None + * + * Transitions: + * - None + * */ + + /* Always allowed */ + rc = SSH_PACKET_ALLOWED; + break; + case SSH2_MSG_UNIMPLEMENTED: // 3 + /* + * States required: + * - None + * + * Transitions: + * - None + * */ + + /* Always allowed */ + rc = SSH_PACKET_ALLOWED; + break; + case SSH2_MSG_DEBUG: // 4 + /* + * States required: + * - None + * + * Transitions: + * - None + * */ + + /* Always allowed */ + rc = SSH_PACKET_ALLOWED; + break; + case SSH2_MSG_SERVICE_REQUEST: // 5 + /* Server only */ + + /* + * States required: + * - session->session_state == SSH_SESSION_STATE_AUTHENTICATING + * or session->session_state == SSH_SESSION_STATE_AUTHENTICATED + * - session->dh_handshake_state == DH_STATE_FINISHED + * + * Transitions: + * - None + * */ + + /* If this is a client, reject the message */ + if (session->client) { + rc = SSH_PACKET_DENIED; + break; + } + + if ((session->session_state != SSH_SESSION_STATE_AUTHENTICATING) && + (session->session_state != SSH_SESSION_STATE_AUTHENTICATED)) + { + rc = SSH_PACKET_DENIED; + break; + } + + if (session->dh_handshake_state != DH_STATE_FINISHED) { + rc = SSH_PACKET_DENIED; + break; + } + + rc = SSH_PACKET_ALLOWED; + break; + case SSH2_MSG_SERVICE_ACCEPT: // 6 + /* + * States required: + * - session->session_state == SSH_SESSION_STATE_AUTHENTICATING + * or session->session_state == SSH_SESSION_STATE_AUTHENTICATED + * - session->dh_handshake_state == DH_STATE_FINISHED + * - session->auth_service_state == SSH_AUTH_SERVICE_SENT + * + * Transitions: + * - auth_service_state = SSH_AUTH_SERVICE_ACCEPTED + * */ + + if ((session->session_state != SSH_SESSION_STATE_AUTHENTICATING) && + (session->session_state != SSH_SESSION_STATE_AUTHENTICATED)) + { + rc = SSH_PACKET_DENIED; + break; + } + + if (session->dh_handshake_state != DH_STATE_FINISHED) { + rc = SSH_PACKET_DENIED; + break; + } + + /* TODO check if only auth service can be requested */ + if (session->auth_service_state != SSH_AUTH_SERVICE_SENT) { + rc = SSH_PACKET_DENIED; + break; + } + + rc = SSH_PACKET_ALLOWED; + break; + case SSH2_MSG_KEXINIT: // 20 + /* + * States required: + * - session_state == SSH_SESSION_STATE_AUTHENTICATED + * or session_state == SSH_SESSION_STATE_INITIAL_KEX + * - dh_handshake_state == DH_STATE_INIT + * or dh_handshake_state == DH_STATE_FINISHED (re-exchange) + * + * Transitions: + * - session->dh_handshake_state = DH_STATE_INIT + * - session->session_state = SSH_SESSION_STATE_KEXINIT_RECEIVED + * + * On server: + * - session->session_state = SSH_SESSION_STATE_DH + * */ + + if ((session->session_state != SSH_SESSION_STATE_AUTHENTICATED) && + (session->session_state != SSH_SESSION_STATE_INITIAL_KEX)) + { + rc = SSH_PACKET_DENIED; + break; + } + + if ((session->dh_handshake_state != DH_STATE_INIT) && + (session->dh_handshake_state != DH_STATE_FINISHED)) + { + rc = SSH_PACKET_DENIED; + } + + rc = SSH_PACKET_ALLOWED; + break; + case SSH2_MSG_NEWKEYS: // 21 + /* + * States required: + * - session_state == SSH_SESSION_STATE_DH + * - dh_handshake_state == DH_STATE_NEWKEYS_SENT + * + * Transitions: + * - session->dh_handshake_state = DH_STATE_FINISHED + * - session->session_state = SSH_SESSION_STATE_AUTHENTICATING + * if session->flags & SSH_SESSION_FLAG_AUTHENTICATED + * - session->session_state = SSH_SESSION_STATE_AUTHENTICATED + * */ + + /* If DH has not been started, reject message */ + if (session->session_state != SSH_SESSION_STATE_DH) { + rc = SSH_PACKET_DENIED; + break; + } + + /* Only allowed if dh_handshake_state is in NEWKEYS_SENT state */ + if (session->dh_handshake_state != DH_STATE_NEWKEYS_SENT) { + rc = SSH_PACKET_DENIED; + break; + } + + rc = SSH_PACKET_ALLOWED; + break; + case SSH2_MSG_KEXDH_INIT: // 30 + // SSH2_MSG_KEX_ECDH_INIT: // 30 + // SSH2_MSG_ECMQV_INIT: // 30 + // SSH2_MSG_KEX_DH_GEX_REQUEST_OLD: // 30 + + /* Server only */ + + /* + * States required: + * - session_state == SSH_SESSION_STATE_DH + * - dh_handshake_state == DH_STATE_INIT + * + * Transitions: + * - session->dh_handshake_state = DH_STATE_INIT_SENT + * then calls dh_handshake_server which triggers: + * - session->dh_handhsake_state = DH_STATE_NEWKEYS_SENT + * */ + + if (session->session_state != SSH_SESSION_STATE_DH) { + rc = SSH_PACKET_DENIED; + break; + } + + /* Only allowed if dh_handshake_state is in initial state */ + if (session->dh_handshake_state != DH_STATE_INIT) { + rc = SSH_PACKET_DENIED; + break; + } + + rc = SSH_PACKET_ALLOWED; + break; + case SSH2_MSG_KEXDH_REPLY: // 31 + // SSH2_MSG_KEX_ECDH_REPLY: // 31 + // SSH2_MSG_ECMQV_REPLY: // 31 + // SSH2_MSG_KEX_DH_GEX_GROUP: // 31 + + /* + * States required: + * - session_state == SSH_SESSION_STATE_DH + * - dh_handshake_state == DH_STATE_INIT_SENT + * + * Transitions: + * - session->dh_handhsake_state = DH_STATE_NEWKEYS_SENT + * */ + + if (session->session_state != SSH_SESSION_STATE_DH) { + rc = SSH_PACKET_DENIED; + break; + } + + if (session->dh_handshake_state != DH_STATE_INIT_SENT) { + rc = SSH_PACKET_DENIED; + break; + } + + rc = SSH_PACKET_ALLOWED; + break; + case SSH2_MSG_KEX_DH_GEX_INIT: // 32 + /* TODO Not filtered */ + rc = SSH_PACKET_ALLOWED; + break; + case SSH2_MSG_KEX_DH_GEX_REPLY: // 33 + /* TODO Not filtered */ + rc = SSH_PACKET_ALLOWED; + break; + case SSH2_MSG_KEX_DH_GEX_REQUEST: // 34 + /* TODO Not filtered */ + rc = SSH_PACKET_ALLOWED; + break; + case SSH2_MSG_USERAUTH_REQUEST: // 50 + /* Server only */ + + /* + * States required: + * - session_state == SSH_SESSION_STATE_AUTHENTICATING + * - dh_hanshake_state == DH_STATE_FINISHED + * + * Transitions: + * - if authentication was successful: + * - session_state = SSH_SESSION_STATE_AUTHENTICATED + * */ + + /* If this is a client, reject the message */ + if (session->client) { + rc = SSH_PACKET_DENIED; + break; + } + + if (session->dh_handshake_state != DH_STATE_FINISHED) { + rc = SSH_PACKET_DENIED; + break; + } + + if (session->session_state != SSH_SESSION_STATE_AUTHENTICATING) { + rc = SSH_PACKET_DENIED; + break; + } + + rc = SSH_PACKET_ALLOWED; + break; + case SSH2_MSG_USERAUTH_FAILURE: // 51 + /* + * States required: + * - session_state == SSH_SESSION_STATE_AUTHENTICATING + * - dh_hanshake_state == DH_STATE_FINISHED + * - session->auth_state == SSH_AUTH_STATE_KBDINT_SENT + * or session->auth_state == SSH_AUTH_STATE_PUBKEY_OFFER_SENT + * or session->auth_state == SSH_AUTH_STATE_PUBKEY_AUTH_SENT + * or session->auth_state == SSH_AUTH_STATE_PASSWORD_AUTH_SENT + * or session->auth_state == SSH_AUTH_STATE_GSSAPI_MIC_SENT + * + * Transitions: + * - if unpacking failed: + * - session->auth_state = SSH_AUTH_ERROR + * - if failure was partial: + * - session->auth_state = SSH_AUTH_PARTIAL + * - else: + * - session->auth_state = SSH_AUTH_STATE_FAILED + * */ + + /* If this is a server, reject the message */ + if (session->server) { + rc = SSH_PACKET_DENIED; + break; + } + + if (session->dh_handshake_state != DH_STATE_FINISHED) { + rc = SSH_PACKET_DENIED; + break; + } + + if (session->session_state != SSH_SESSION_STATE_AUTHENTICATING) { + rc = SSH_PACKET_DENIED; + break; + } + + rc = SSH_PACKET_ALLOWED; + break; + case SSH2_MSG_USERAUTH_SUCCESS: // 52 + /* + * States required: + * - session_state == SSH_SESSION_STATE_AUTHENTICATING + * - dh_hanshake_state == DH_STATE_FINISHED + * - session->auth_state == SSH_AUTH_STATE_KBDINT_SENT + * or session->auth_state == SSH_AUTH_STATE_PUBKEY_AUTH_SENT + * or session->auth_state == SSH_AUTH_STATE_PASSWORD_AUTH_SENT + * or session->auth_state == SSH_AUTH_STATE_GSSAPI_MIC_SENT + * or session->auth_state == SSH_AUTH_STATE_AUTH_NONE_SENT + * + * Transitions: + * - session->auth_state = SSH_AUTH_STATE_SUCCESS + * - session->session_state = SSH_SESSION_STATE_AUTHENTICATED + * - session->flags |= SSH_SESSION_FLAG_AUTHENTICATED + * - sessions->auth.current_method = SSH_AUTH_METHOD_UNKNOWN + * */ + + /* If this is a server, reject the message */ + if (session->server) { + rc = SSH_PACKET_DENIED; + break; + } + + if (session->dh_handshake_state != DH_STATE_FINISHED) { + rc = SSH_PACKET_DENIED; + break; + } + + if (session->session_state != SSH_SESSION_STATE_AUTHENTICATING) { + rc = SSH_PACKET_DENIED; + break; + } + + if ((session->auth_state != SSH_AUTH_STATE_KBDINT_SENT) && + (session->auth_state != SSH_AUTH_STATE_PUBKEY_AUTH_SENT) && + (session->auth_state != SSH_AUTH_STATE_PASSWORD_AUTH_SENT) && + (session->auth_state != SSH_AUTH_STATE_GSSAPI_MIC_SENT) && + (session->auth_state != SSH_AUTH_STATE_AUTH_NONE_SENT)) + { + rc = SSH_PACKET_DENIED; + break; + } + + rc = SSH_PACKET_ALLOWED; + break; + case SSH2_MSG_USERAUTH_BANNER: // 53 + /* + * States required: + * - session_state == SSH_SESSION_STATE_AUTHENTICATING + * + * Transitions: + * - None + * */ + + if (session->session_state != SSH_SESSION_STATE_AUTHENTICATING) { + rc = SSH_PACKET_DENIED; + break; + } + + rc = SSH_PACKET_ALLOWED; + break; + case SSH2_MSG_USERAUTH_PK_OK: // 60 + // SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ: // 60 + // SSH2_MSG_USERAUTH_INFO_REQUEST: // 60 + // SSH2_MSG_USERAUTH_GSSAPI_RESPONSE: // 60 + + /* + * States required: + * - session_state == SSH_SESSION_STATE_AUTHENTICATING + * - session->auth_state == SSH_AUTH_STATE_KBDINT_SENT + * or + * session->auth_state == SSH_AUTH_STATE_GSSAPI_REQUEST_SENT + * or + * session->auth_state == SSH_AUTH_STATE_PUBKEY_OFFER_SENT + * + * Transitions: + * Depending on the current state, the message is treated + * differently: + * - session->auth_state == SSH_AUTH_STATE_KBDINT_SENT + * - session->auth_state = SSH_AUTH_STATE_INFO + * - session->auth_state == SSH_AUTH_STATE_GSSAPI_REQUEST_SENT + * - session->auth_state = SSH_AUTH_STATE_GSSAPI_TOKEN + * - session->auth_state == SSH_AUTH_STATE_PUBKEY_OFFER_SENT + * - session->auth_state = SSH_AUTH_STATE_PK_OK + * */ + + if (session->session_state != SSH_SESSION_STATE_AUTHENTICATING) { + rc = SSH_PACKET_DENIED; + break; + } + + if ((session->auth_state != SSH_AUTH_STATE_KBDINT_SENT) && + (session->auth_state != SSH_AUTH_STATE_PUBKEY_OFFER_SENT) && + (session->auth_state != SSH_AUTH_STATE_GSSAPI_REQUEST_SENT)) + { + rc = SSH_PACKET_DENIED; + break; + } + + rc = SSH_PACKET_ALLOWED; + break; + case SSH2_MSG_USERAUTH_INFO_RESPONSE: // 61 + // SSH2_MSG_USERAUTH_GSSAPI_TOKEN: // 61 + + /* + * States required: + * - session_state == SSH_SESSION_STATE_AUTHENTICATING + * - session_state->auth_state == SSH_SESSION_STATE_GSSAPI_TOKEN + * or + * session_state->auth_state == SSH_SESSION_STATE_INFO + * + * Transitions: + * - None + * */ + + if (session->session_state != SSH_SESSION_STATE_AUTHENTICATING) { + rc = SSH_PACKET_DENIED; + break; + } + + if ((session->auth_state != SSH_AUTH_STATE_INFO) && + (session->auth_state != SSH_AUTH_STATE_GSSAPI_TOKEN)) + { + rc = SSH_PACKET_DENIED; + break; + } + + rc = SSH_PACKET_ALLOWED; + break; + case SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE: // 63 + /* TODO Not filtered */ + rc = SSH_PACKET_ALLOWED; + break; + case SSH2_MSG_USERAUTH_GSSAPI_ERROR: // 64 + /* TODO Not filtered */ + rc = SSH_PACKET_ALLOWED; + break; + case SSH2_MSG_USERAUTH_GSSAPI_ERRTOK: // 65 + /* TODO Not filtered */ + rc = SSH_PACKET_ALLOWED; + break; + case SSH2_MSG_USERAUTH_GSSAPI_MIC: // 66 + /* Server only */ + + /* + * States required: + * - session_state == SSH_SESSION_STATE_AUTHENTICATING + * - session->gssapi->state == SSH_GSSAPI_STATE_RCV_MIC + * + * Transitions: + * Depending on the result of the verification, the states are + * changed: + * - SSH_AUTH_SUCCESS: + * - session->session_state = SSH_SESSION_STATE_AUTHENTICATED + * - session->flags != SSH_SESSION_FLAG_AUTHENTICATED + * - SSH_AUTH_PARTIAL: + * - None + * - any other case: + * - None + * */ + + /* If this is a client, reject the message */ + if (session->client) { + rc = SSH_PACKET_DENIED; + break; + } + + if (session->dh_handshake_state != DH_STATE_FINISHED) { + rc = SSH_PACKET_DENIED; + break; + } + + if (session->session_state != SSH_SESSION_STATE_AUTHENTICATING) { + rc = SSH_PACKET_DENIED; + break; + } + + rc = SSH_PACKET_ALLOWED; + break; + case SSH2_MSG_GLOBAL_REQUEST: // 80 + /* + * States required: + * - session_state == SSH_SESSION_STATE_AUTHENTICATED + * + * Transitions: + * - None + * */ + + if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) { + rc = SSH_PACKET_DENIED; + break; + } + + rc = SSH_PACKET_ALLOWED; + break; + case SSH2_MSG_REQUEST_SUCCESS: // 81 + /* + * States required: + * - session_state == SSH_SESSION_STATE_AUTHENTICATED + * - session->global_req_state == SSH_CHANNEL_REQ_STATE_PENDING + * + * Transitions: + * - session->global_req_state == SSH_CHANNEL_REQ_STATE_ACCEPTED + * */ + + if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) { + rc = SSH_PACKET_DENIED; + break; + } + + if (session->global_req_state != SSH_CHANNEL_REQ_STATE_PENDING) { + rc = SSH_PACKET_DENIED; + break; + } + + rc = SSH_PACKET_ALLOWED; + break; + case SSH2_MSG_REQUEST_FAILURE: // 82 + /* + * States required: + * - session_state == SSH_SESSION_STATE_AUTHENTICATED + * - session->global_req_state == SSH_CHANNEL_REQ_STATE_PENDING + * + * Transitions: + * - session->global_req_state == SSH_CHANNEL_REQ_STATE_DENIED + * */ + + if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) { + rc = SSH_PACKET_DENIED; + break; + } + + if (session->global_req_state != SSH_CHANNEL_REQ_STATE_PENDING) { + rc = SSH_PACKET_DENIED; + break; + } + + rc = SSH_PACKET_ALLOWED; + break; + case SSH2_MSG_CHANNEL_OPEN: // 90 + /* + * States required: + * - session_state == SSH_SESSION_STATE_AUTHENTICATED + * + * Transitions: + * - None + * */ + + if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) { + rc = SSH_PACKET_DENIED; + break; + } + + rc = SSH_PACKET_ALLOWED; + break; + case SSH2_MSG_CHANNEL_OPEN_CONFIRMATION: // 91 + /* + * States required: + * - session_state == SSH_SESSION_STATE_AUTHENTICATED + * + * Transitions: + * - channel->state = SSH_CHANNEL_STATE_OPEN + * - channel->flags &= ~SSH_CHANNEL_FLAG_NOT_BOUND + * */ + + if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) { + rc = SSH_PACKET_DENIED; + break; + } + + rc = SSH_PACKET_ALLOWED; + break; + case SSH2_MSG_CHANNEL_OPEN_FAILURE: // 92 + /* + * States required: + * - session_state == SSH_SESSION_STATE_AUTHENTICATED + * + * Transitions: + * - channel->state = SSH_CHANNEL_STATE_OPEN_DENIED + * */ + + if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) { + rc = SSH_PACKET_DENIED; + break; + } + + rc = SSH_PACKET_ALLOWED; + break; + case SSH2_MSG_CHANNEL_WINDOW_ADJUST: // 93 + /* + * States required: + * - session_state == SSH_SESSION_STATE_AUTHENTICATED + * + * Transitions: + * - None + * */ + + if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) { + rc = SSH_PACKET_DENIED; + break; + } + + rc = SSH_PACKET_ALLOWED; + break; + case SSH2_MSG_CHANNEL_DATA: // 94 + /* + * States required: + * - session_state == SSH_SESSION_STATE_AUTHENTICATED + * + * Transitions: + * - None + * */ + + if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) { + rc = SSH_PACKET_DENIED; + break; + } + + rc = SSH_PACKET_ALLOWED; + break; + case SSH2_MSG_CHANNEL_EXTENDED_DATA: // 95 + /* + * States required: + * - session_state == SSH_SESSION_STATE_AUTHENTICATED + * + * Transitions: + * - None + * */ + + if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) { + rc = SSH_PACKET_DENIED; + break; + } + + rc = SSH_PACKET_ALLOWED; + break; + case SSH2_MSG_CHANNEL_EOF: // 96 + /* + * States required: + * - session_state == SSH_SESSION_STATE_AUTHENTICATED + * + * Transitions: + * - None + * */ + + if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) { + rc = SSH_PACKET_DENIED; + break; + } + + rc = SSH_PACKET_ALLOWED; + break; + case SSH2_MSG_CHANNEL_CLOSE: // 97 + /* + * States required: + * - session_state == SSH_SESSION_STATE_AUTHENTICATED + * + * Transitions: + * - channel->state = SSH_CHANNEL_STATE_CLOSED + * - channel->flags |= SSH_CHANNEL_FLAG_CLOSED_REMOTE + * */ + + if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) { + rc = SSH_PACKET_DENIED; + break; + } + + rc = SSH_PACKET_ALLOWED; + break; + case SSH2_MSG_CHANNEL_REQUEST: // 98 + /* + * States required: + * - session_state == SSH_SESSION_STATE_AUTHENTICATED + * + * Transitions: + * - Depends on the request + * */ + + if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) { + rc = SSH_PACKET_DENIED; + break; + } + + rc = SSH_PACKET_ALLOWED; + break; + case SSH2_MSG_CHANNEL_SUCCESS: // 99 + /* + * States required: + * - session_state == SSH_SESSION_STATE_AUTHENTICATED + * - channel->request_state == SSH_CHANNEL_REQ_STATE_PENDING + * + * Transitions: + * - channel->request_state = SSH_CHANNEL_REQ_STATE_ACCEPTED + * */ + + if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) { + rc = SSH_PACKET_DENIED; + break; + } + + rc = SSH_PACKET_ALLOWED; + break; + case SSH2_MSG_CHANNEL_FAILURE: // 100 + /* + * States required: + * - session_state == SSH_SESSION_STATE_AUTHENTICATED + * - channel->request_state == SSH_CHANNEL_REQ_STATE_PENDING + * + * Transitions: + * - channel->request_state = SSH_CHANNEL_REQ_STATE_DENIED + * */ + + if (session->session_state != SSH_SESSION_STATE_AUTHENTICATED) { + rc = SSH_PACKET_DENIED; + break; + } + + rc = SSH_PACKET_ALLOWED; + break; + default: + /* Unknown message, do not filter */ + rc = SSH_PACKET_UNKNOWN; + goto end; + } + +end: +#ifdef DEBUG_PACKET + if (rc == SSH_PACKET_DENIED) { + SSH_LOG(SSH_LOG_PACKET, "REJECTED packet type %d: ", + session->in_packet.type); + } + + if (rc == SSH_PACKET_UNKNOWN) { + SSH_LOG(SSH_LOG_PACKET, "UNKNOWN packet type %d", + session->in_packet.type); + } +#endif + + return rc; +} + /* in nonblocking mode, socket_read will read as much as it can, and return */ /* SSH_OK if it has read at least len bytes, otherwise, SSH_AGAIN. */ /* in blocking mode, it will read at least len bytes and will block until it's ok. */ @@ -153,6 +922,7 @@ int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user) uint32_t len, compsize, payloadsize; uint8_t padding; size_t processed = 0; /* number of byte processed from the callback */ + enum ssh_packet_filter_result_e filter_result; if(session->current_crypto != NULL) { current_macsize = hmac_digest_len(session->current_crypto->in_hmac); @@ -328,8 +1098,21 @@ int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user) "packet: read type %hhd [len=%d,padding=%hhd,comp=%d,payload=%d]", session->in_packet.type, len, padding, compsize, payloadsize); - /* Execute callbacks */ - ssh_packet_process(session, session->in_packet.type); + /* Check if the packet is expected */ + filter_result = ssh_packet_incoming_filter(session); + + switch(filter_result) { + case SSH_PACKET_ALLOWED: + /* Execute callbacks */ + ssh_packet_process(session, session->in_packet.type); + break; + case SSH_PACKET_DENIED: + goto error; + case SSH_PACKET_UNKNOWN: + ssh_packet_send_unimplemented(session, session->recv_seq - 1); + break; + } + session->packet_state = PACKET_STATE_INIT; if (processed < receivedlen) { /* Handle a potential packet left in socket buffer */ |