packet.c | packet.c | |||
---|---|---|---|---|
skipping to change at line 24 | skipping to change at line 24 | |||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILI TY | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILI TY | |||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public | |||
* License for more details. | * License for more details. | |||
* | * | |||
* You should have received a copy of the GNU Lesser General Public License | * You should have received a copy of the GNU Lesser General Public License | |||
* along with the SSH Library; see the file COPYING. If not, write to | * along with the SSH Library; see the file COPYING. If not, write to | |||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, | * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, | |||
* MA 02111-1307, USA. | * MA 02111-1307, USA. | |||
*/ | */ | |||
#include "config.h" | ||||
#include <stdlib.h> | #include <stdlib.h> | |||
#include <stdio.h> | #include <stdio.h> | |||
#include <unistd.h> | ||||
#include <string.h> | #include <string.h> | |||
#include <errno.h> | #include <errno.h> | |||
#ifndef _WIN32 | #ifndef _WIN32 | |||
#include <arpa/inet.h> | #include <arpa/inet.h> | |||
#endif | #endif | |||
#include "config.h" | ||||
#include "libssh/priv.h" | #include "libssh/priv.h" | |||
#include "libssh/ssh2.h" | #include "libssh/ssh2.h" | |||
#include "libssh/ssh1.h" | #include "libssh/ssh1.h" | |||
#include "libssh/crypto.h" | #include "libssh/crypto.h" | |||
#include "libssh/buffer.h" | ||||
#include "libssh/packet.h" | ||||
#include "libssh/socket.h" | ||||
#include "libssh/channels.h" | ||||
#include "libssh/session.h" | ||||
#include "libssh/messages.h" | ||||
#include "libssh/pcap.h" | ||||
/* XXX include selected mac size */ | /* XXX include selected mac size */ | |||
static int macsize=SHA_DIGEST_LEN; | static int macsize=SHA_DIGEST_LEN; | |||
/* in nonblocking mode, socket_read will read as much as it can, and return */ | /* 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. */ | /* 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 i t's ok. */ | /* in blocking mode, it will read at least len bytes and will block until i t's ok. */ | |||
#define PACKET_STATE_INIT 0 | #define PACKET_STATE_INIT 0 | |||
#define PACKET_STATE_SIZEREAD 1 | #define PACKET_STATE_SIZEREAD 1 | |||
static int packet_read2(SSH_SESSION *session) { | static int packet_read2(ssh_session session) { | |||
unsigned int blocksize = (session->current_crypto ? | unsigned int blocksize = (session->current_crypto ? | |||
session->current_crypto->in_cipher->blocksize : 8); | session->current_crypto->in_cipher->blocksize : 8); | |||
int current_macsize = session->current_crypto ? macsize : 0; | int current_macsize = session->current_crypto ? macsize : 0; | |||
unsigned char mac[30] = {0}; | unsigned char mac[30] = {0}; | |||
char buffer[16] = {0}; | char buffer[16] = {0}; | |||
void *packet=NULL; | void *packet=NULL; | |||
int to_be_read; | int to_be_read; | |||
int rc = SSH_ERROR; | int rc = SSH_ERROR; | |||
u32 len; | uint32_t len; | |||
u8 padding; | uint8_t padding; | |||
enter_function(); | enter_function(); | |||
if (session->alive == 0) { | if (session->alive == 0) { | |||
/* The error message was already set into this session */ | /* The error message was already set into this session */ | |||
leave_function(); | leave_function(); | |||
return SSH_ERROR; | return SSH_ERROR; | |||
} | } | |||
switch(session->packet_state) { | switch(session->packet_state) { | |||
skipping to change at line 105 | skipping to change at line 112 | |||
if (buffer_add_data(session->in_buffer, buffer, blocksize) < 0) { | if (buffer_add_data(session->in_buffer, buffer, blocksize) < 0) { | |||
goto error; | goto error; | |||
} | } | |||
if(len > MAX_PACKET_LEN) { | if(len > MAX_PACKET_LEN) { | |||
ssh_set_error(session, SSH_FATAL, | ssh_set_error(session, SSH_FATAL, | |||
"read_packet(): Packet len too high(%u %.4x)", len, len); | "read_packet(): Packet len too high(%u %.4x)", len, len); | |||
goto error; | goto error; | |||
} | } | |||
to_be_read = len - blocksize + sizeof(u32); | to_be_read = len - blocksize + sizeof(uint32_t); | |||
if (to_be_read < 0) { | if (to_be_read < 0) { | |||
/* remote sshd sends invalid sizes? */ | /* remote sshd sends invalid sizes? */ | |||
ssh_set_error(session, SSH_FATAL, | ssh_set_error(session, SSH_FATAL, | |||
"given numbers of bytes left to be read < 0 (%d)!", to_be_read) ; | "given numbers of bytes left to be read < 0 (%d)!", to_be_read) ; | |||
goto error; | goto error; | |||
} | } | |||
/* saves the status of the current operations */ | /* saves the status of the current operations */ | |||
session->in_packet.len = len; | session->in_packet.len = len; | |||
session->packet_state = PACKET_STATE_SIZEREAD; | session->packet_state = PACKET_STATE_SIZEREAD; | |||
case PACKET_STATE_SIZEREAD: | case PACKET_STATE_SIZEREAD: | |||
len = session->in_packet.len; | len = session->in_packet.len; | |||
to_be_read = len - blocksize + sizeof(u32) + current_macsize; | to_be_read = len - blocksize + sizeof(uint32_t) + current_macsize; | |||
/* if to_be_read is zero, the whole packet was blocksize bytes. */ | /* if to_be_read is zero, the whole packet was blocksize bytes. */ | |||
if (to_be_read != 0) { | if (to_be_read != 0) { | |||
rc = ssh_socket_wait_for_data(session->socket,session,to_be_read); | rc = ssh_socket_wait_for_data(session->socket,session,to_be_read); | |||
if (rc != SSH_OK) { | if (rc != SSH_OK) { | |||
goto error; | goto error; | |||
} | } | |||
rc = SSH_ERROR; | rc = SSH_ERROR; | |||
packet = malloc(to_be_read); | packet = malloc(to_be_read); | |||
if (packet == NULL) { | if (packet == NULL) { | |||
skipping to change at line 150 | skipping to change at line 157 | |||
} | } | |||
SAFE_FREE(packet); | SAFE_FREE(packet); | |||
} | } | |||
if (session->current_crypto) { | if (session->current_crypto) { | |||
/* | /* | |||
* decrypt the rest of the packet (blocksize bytes already | * decrypt the rest of the packet (blocksize bytes already | |||
* have been decrypted) | * have been decrypted) | |||
*/ | */ | |||
if (packet_decrypt(session, | if (packet_decrypt(session, | |||
buffer_get(session->in_buffer) + blocksize, | ((uint8_t*)buffer_get(session->in_buffer) + blocksize), | |||
buffer_get_len(session->in_buffer) - blocksize) < 0) { | buffer_get_len(session->in_buffer) - blocksize) < 0) { | |||
ssh_set_error(session, SSH_FATAL, "Decrypt error"); | ssh_set_error(session, SSH_FATAL, "Decrypt error"); | |||
goto error; | goto error; | |||
} | } | |||
#ifdef WITH_PCAP | ||||
if(session->pcap_ctx){ | ||||
ssh_pcap_context_write(session->pcap_ctx, | ||||
SSH_PCAP_DIR_IN, buffer_get(session->in_buff | ||||
er), | ||||
buffer_get_len(session->in_buffer), | ||||
buffer_get_len(session->in_buffer)); | ||||
} | ||||
#endif | ||||
ssh_socket_read(session->socket, mac, macsize); | ssh_socket_read(session->socket, mac, macsize); | |||
if (packet_hmac_verify(session, session->in_buffer, mac) < 0) { | if (packet_hmac_verify(session, session->in_buffer, mac) < 0) { | |||
ssh_set_error(session, SSH_FATAL, "HMAC error"); | ssh_set_error(session, SSH_FATAL, "HMAC error"); | |||
goto error; | goto error; | |||
} | } | |||
} | } | |||
#ifdef WITH_PCAP | ||||
else { | ||||
/* No crypto */ | ||||
if(session->pcap_ctx){ | ||||
ssh_pcap_context_write(session->pcap_ctx, | ||||
SSH_PCAP_DIR_IN, buffer_get(session->in_buff | ||||
er), | ||||
buffer_get_len(session->in_buffer), | ||||
buffer_get_len(session->in_buffer)); | ||||
} | ||||
} | ||||
#endif | ||||
buffer_pass_bytes(session->in_buffer, sizeof(u32)); | buffer_pass_bytes(session->in_buffer, sizeof(uint32_t)); | |||
/* pass the size which has been processed before */ | /* pass the size which has been processed before */ | |||
if (buffer_get_u8(session->in_buffer, &padding) == 0) { | if (buffer_get_u8(session->in_buffer, &padding) == 0) { | |||
ssh_set_error(session, SSH_FATAL, "Packet too short to read padding "); | ssh_set_error(session, SSH_FATAL, "Packet too short to read padding "); | |||
goto error; | goto error; | |||
} | } | |||
ssh_log(session, SSH_LOG_RARE, | ssh_log(session, SSH_LOG_PACKET, | |||
"%hhd bytes padding, %d bytes left in buffer", | "%hhd bytes padding, %d bytes left in buffer", | |||
padding, buffer_get_rest_len(session->in_buffer)); | padding, buffer_get_rest_len(session->in_buffer)); | |||
if (padding > buffer_get_rest_len(session->in_buffer)) { | if (padding > buffer_get_rest_len(session->in_buffer)) { | |||
ssh_set_error(session, SSH_FATAL, | ssh_set_error(session, SSH_FATAL, | |||
"Invalid padding: %d (%d resting)", | "Invalid padding: %d (%d resting)", | |||
padding, | padding, | |||
buffer_get_rest_len(session->in_buffer)); | buffer_get_rest_len(session->in_buffer)); | |||
#ifdef DEBUG_CRYPTO | #ifdef DEBUG_CRYPTO | |||
ssh_print_hexa("incrimined packet", | ssh_print_hexa("incrimined packet", | |||
buffer_get(session->in_buffer), | buffer_get(session->in_buffer), | |||
buffer_get_len(session->in_buffer)); | buffer_get_len(session->in_buffer)); | |||
#endif | #endif | |||
goto error; | goto error; | |||
} | } | |||
buffer_pass_bytes_end(session->in_buffer, padding); | buffer_pass_bytes_end(session->in_buffer, padding); | |||
ssh_log(session, SSH_LOG_RARE, | ssh_log(session, SSH_LOG_PACKET, | |||
"After padding, %d bytes left in buffer", | "After padding, %d bytes left in buffer", | |||
buffer_get_rest_len(session->in_buffer)); | buffer_get_rest_len(session->in_buffer)); | |||
#if defined(HAVE_LIBZ) && defined(WITH_LIBZ) | #if defined(HAVE_LIBZ) && defined(WITH_LIBZ) | |||
if (session->current_crypto && session->current_crypto->do_compress_i n) { | if (session->current_crypto && session->current_crypto->do_compress_i n) { | |||
ssh_log(session, SSH_LOG_RARE, "Decompressing in_buffer ..."); | ssh_log(session, SSH_LOG_PACKET, "Decompressing in_buffer ..."); | |||
if (decompress_buffer(session, session->in_buffer) < 0) { | if (decompress_buffer(session, session->in_buffer, MAX_PACKET_LEN) | |||
< 0) { | ||||
goto error; | goto error; | |||
} | } | |||
} | } | |||
#endif | #endif | |||
session->recv_seq++; | session->recv_seq++; | |||
session->packet_state = PACKET_STATE_INIT; | session->packet_state = PACKET_STATE_INIT; | |||
leave_function(); | leave_function(); | |||
return SSH_OK; | return SSH_OK; | |||
} | } | |||
skipping to change at line 218 | skipping to change at line 244 | |||
"Invalid state into packet_read2(): %d", | "Invalid state into packet_read2(): %d", | |||
session->packet_state); | session->packet_state); | |||
error: | error: | |||
leave_function(); | leave_function(); | |||
return rc; | return rc; | |||
} | } | |||
#ifdef WITH_SSH1 | #ifdef WITH_SSH1 | |||
/* a slighty modified packet_read2() for SSH-1 protocol */ | /* a slighty modified packet_read2() for SSH-1 protocol */ | |||
static int packet_read1(SSH_SESSION *session) { | static int packet_read1(ssh_session session) { | |||
void *packet = NULL; | void *packet = NULL; | |||
int rc = SSH_ERROR; | int rc = SSH_ERROR; | |||
int to_be_read; | int to_be_read; | |||
u32 padding; | uint32_t padding; | |||
u32 crc; | uint32_t crc; | |||
u32 len; | uint32_t len; | |||
enter_function(); | enter_function(); | |||
if(!session->alive) { | if(!session->alive) { | |||
goto error; | goto error; | |||
} | } | |||
switch (session->packet_state){ | switch (session->packet_state){ | |||
case PACKET_STATE_INIT: | case PACKET_STATE_INIT: | |||
memset(&session->in_packet, 0, sizeof(PACKET)); | memset(&session->in_packet, 0, sizeof(PACKET)); | |||
skipping to change at line 247 | skipping to change at line 273 | |||
if (buffer_reinit(session->in_buffer) < 0) { | if (buffer_reinit(session->in_buffer) < 0) { | |||
goto error; | goto error; | |||
} | } | |||
} else { | } else { | |||
session->in_buffer = buffer_new(); | session->in_buffer = buffer_new(); | |||
if (session->in_buffer == NULL) { | if (session->in_buffer == NULL) { | |||
goto error; | goto error; | |||
} | } | |||
} | } | |||
rc = ssh_socket_read(session->socket, &len, sizeof(u32)); | rc = ssh_socket_read(session->socket, &len, sizeof(uint32_t)); | |||
if (rc != SSH_OK) { | if (rc != SSH_OK) { | |||
goto error; | goto error; | |||
} | } | |||
rc = SSH_ERROR; | rc = SSH_ERROR; | |||
/* len is not encrypted */ | /* len is not encrypted */ | |||
len = ntohl(len); | len = ntohl(len); | |||
if (len > MAX_PACKET_LEN) { | if (len > MAX_PACKET_LEN) { | |||
ssh_set_error(session, SSH_FATAL, | ssh_set_error(session, SSH_FATAL, | |||
skipping to change at line 314 | skipping to change at line 340 | |||
ssh_set_error(session, SSH_FATAL, "Packet decrypt error"); | ssh_set_error(session, SSH_FATAL, "Packet decrypt error"); | |||
goto error; | goto error; | |||
} | } | |||
} | } | |||
#ifdef DEBUG_CRYPTO | #ifdef DEBUG_CRYPTO | |||
ssh_print_hexa("read packet decrypted:", buffer_get(session->in_buffe r), | ssh_print_hexa("read packet decrypted:", buffer_get(session->in_buffe r), | |||
buffer_get_len(session->in_buffer)); | buffer_get_len(session->in_buffer)); | |||
#endif | #endif | |||
ssh_log(session, SSH_LOG_PACKET, "%d bytes padding", padding); | ssh_log(session, SSH_LOG_PACKET, "%d bytes padding", padding); | |||
if(((len + padding) != buffer_get_rest_len(session->in_buffer)) || | if(((len + padding) != buffer_get_rest_len(session->in_buffer)) || | |||
((len + padding) < sizeof(u32))) { | ((len + padding) < sizeof(uint32_t))) { | |||
ssh_log(session, SSH_LOG_RARE, "no crc32 in packet"); | ssh_log(session, SSH_LOG_RARE, "no crc32 in packet"); | |||
ssh_set_error(session, SSH_FATAL, "no crc32 in packet"); | ssh_set_error(session, SSH_FATAL, "no crc32 in packet"); | |||
goto error; | goto error; | |||
} | } | |||
memcpy(&crc, | memcpy(&crc, | |||
buffer_get_rest(session->in_buffer) + (len+padding) - sizeof(u32) | (unsigned char *)buffer_get_rest(session->in_buffer) + (len+paddi | |||
, | ng) - sizeof(uint32_t), | |||
sizeof(u32)); | sizeof(uint32_t)); | |||
buffer_pass_bytes_end(session->in_buffer, sizeof(u32)); | buffer_pass_bytes_end(session->in_buffer, sizeof(uint32_t)); | |||
crc = ntohl(crc); | crc = ntohl(crc); | |||
if (ssh_crc32(buffer_get_rest(session->in_buffer), | if (ssh_crc32(buffer_get_rest(session->in_buffer), | |||
(len + padding) - sizeof(u32)) != crc) { | (len + padding) - sizeof(uint32_t)) != crc) { | |||
#ifdef DEBUG_CRYPTO | #ifdef DEBUG_CRYPTO | |||
ssh_print_hexa("crc32 on",buffer_get_rest(session->in_buffer), | ssh_print_hexa("crc32 on",buffer_get_rest(session->in_buffer), | |||
len + padding - sizeof(u32)); | len + padding - sizeof(uint32_t)); | |||
#endif | #endif | |||
ssh_log(session, SSH_LOG_RARE, "Invalid crc32"); | ssh_log(session, SSH_LOG_RARE, "Invalid crc32"); | |||
ssh_set_error(session, SSH_FATAL, | ssh_set_error(session, SSH_FATAL, | |||
"Invalid crc32: expected %.8x, got %.8x", | "Invalid crc32: expected %.8x, got %.8x", | |||
crc, | crc, | |||
ssh_crc32(buffer_get_rest(session->in_buffer), | ssh_crc32(buffer_get_rest(session->in_buffer), | |||
len + padding - sizeof(u32))); | len + padding - sizeof(uint32_t))); | |||
goto error; | goto error; | |||
} | } | |||
/* pass the padding */ | /* pass the padding */ | |||
buffer_pass_bytes(session->in_buffer, padding); | buffer_pass_bytes(session->in_buffer, padding); | |||
ssh_log(session, SSH_LOG_PACKET, "The packet is valid"); | ssh_log(session, SSH_LOG_PACKET, "The packet is valid"); | |||
/* TODO FIXME | /* TODO FIXME | |||
#if defined(HAVE_LIBZ) && defined(WITH_LIBZ) | #if defined(HAVE_LIBZ) && defined(WITH_LIBZ) | |||
if(session->current_crypto && session->current_crypto->do_compress_in){ | if(session->current_crypto && session->current_crypto->do_compress_in){ | |||
decompress_buffer(session,session->in_buffer); | decompress_buffer(session,session->in_buffer); | |||
skipping to change at line 368 | skipping to change at line 394 | |||
"Invalid state into packet_read1(): %d", | "Invalid state into packet_read1(): %d", | |||
session->packet_state); | session->packet_state); | |||
error: | error: | |||
leave_function(); | leave_function(); | |||
return rc; | return rc; | |||
} | } | |||
#endif /* WITH_SSH1 */ | #endif /* WITH_SSH1 */ | |||
/* that's where i'd like C to be object ... */ | /* that's where i'd like C to be object ... */ | |||
int packet_read(SSH_SESSION *session) { | int packet_read(ssh_session session) { | |||
#ifdef WITH_SSH1 | #ifdef WITH_SSH1 | |||
if (session->version == 1) { | if (session->version == 1) { | |||
return packet_read1(session); | return packet_read1(session); | |||
} | } | |||
#endif | #endif | |||
return packet_read2(session); | return packet_read2(session); | |||
} | } | |||
int packet_translate(SSH_SESSION *session) { | int packet_translate(ssh_session session) { | |||
enter_function(); | enter_function(); | |||
memset(&session->in_packet, 0, sizeof(PACKET)); | memset(&session->in_packet, 0, sizeof(PACKET)); | |||
if(session->in_buffer == NULL) { | if(session->in_buffer == NULL) { | |||
leave_function(); | leave_function(); | |||
return SSH_ERROR; | return SSH_ERROR; | |||
} | } | |||
ssh_log(session, SSH_LOG_RARE, "Final size %d", | ssh_log(session, SSH_LOG_PACKET, "Final size %d", | |||
buffer_get_rest_len(session->in_buffer)); | buffer_get_rest_len(session->in_buffer)); | |||
if(buffer_get_u8(session->in_buffer, &session->in_packet.type) == 0) { | if(buffer_get_u8(session->in_buffer, &session->in_packet.type) == 0) { | |||
ssh_set_error(session, SSH_FATAL, "Packet too short to read type"); | ssh_set_error(session, SSH_FATAL, "Packet too short to read type"); | |||
leave_function(); | leave_function(); | |||
return SSH_ERROR; | return SSH_ERROR; | |||
} | } | |||
ssh_log(session, SSH_LOG_RARE, "Type %hhd", session->in_packet.type); | ssh_log(session, SSH_LOG_PACKET, "Type %hhd", session->in_packet.type); | |||
session->in_packet.valid = 1; | session->in_packet.valid = 1; | |||
leave_function(); | leave_function(); | |||
return SSH_OK; | return SSH_OK; | |||
} | } | |||
/* | /* | |||
* Write the the bufferized output. If the session is blocking, or | * Write the the bufferized output. If the session is blocking, or | |||
* enforce_blocking is set, the call may block. Otherwise, it won't block. | * enforce_blocking is set, the call may block. Otherwise, it won't block. | |||
* Return SSH_OK if everything has been sent, SSH_AGAIN if there are still | * Return SSH_OK if everything has been sent, SSH_AGAIN if there are still | |||
* things to send on buffer, SSH_ERROR if there is an error. | * things to send on buffer, SSH_ERROR if there is an error. | |||
*/ | */ | |||
int packet_flush(SSH_SESSION *session, int enforce_blocking) { | int packet_flush(ssh_session session, int enforce_blocking) { | |||
if (enforce_blocking || session->blocking) { | if (enforce_blocking || session->blocking) { | |||
return ssh_socket_blocking_flush(session->socket); | return ssh_socket_blocking_flush(session->socket); | |||
} | } | |||
return ssh_socket_nonblocking_flush(session->socket); | return ssh_socket_nonblocking_flush(session->socket); | |||
} | } | |||
/* | /* | |||
* This function places the outgoing packet buffer into an outgoing | * This function places the outgoing packet buffer into an outgoing | |||
* socket buffer | * socket buffer | |||
*/ | */ | |||
static int packet_write(SSH_SESSION *session) { | static int packet_write(ssh_session session) { | |||
int rc = SSH_ERROR; | int rc = SSH_ERROR; | |||
enter_function(); | enter_function(); | |||
ssh_socket_write(session->socket, | ssh_socket_write(session->socket, | |||
buffer_get(session->out_buffer), | buffer_get(session->out_buffer), | |||
buffer_get_len(session->out_buffer)); | buffer_get_len(session->out_buffer)); | |||
rc = packet_flush(session, 0); | rc = packet_flush(session, 0); | |||
leave_function(); | leave_function(); | |||
return rc; | return rc; | |||
} | } | |||
static int packet_send2(SSH_SESSION *session) { | static int packet_send2(ssh_session session) { | |||
unsigned int blocksize = (session->current_crypto ? | unsigned int blocksize = (session->current_crypto ? | |||
session->current_crypto->out_cipher->blocksize : 8); | session->current_crypto->out_cipher->blocksize : 8); | |||
u32 currentlen = buffer_get_len(session->out_buffer); | uint32_t currentlen = buffer_get_len(session->out_buffer); | |||
unsigned char *hmac = NULL; | unsigned char *hmac = NULL; | |||
char padstring[32] = {0}; | char padstring[32] = {0}; | |||
int rc = SSH_ERROR; | int rc = SSH_ERROR; | |||
u32 finallen; | uint32_t finallen; | |||
u8 padding; | uint8_t padding; | |||
enter_function(); | enter_function(); | |||
ssh_log(session, SSH_LOG_RARE, | ssh_log(session, SSH_LOG_PACKET, | |||
"Writing on the wire a packet having %u bytes before", currentlen); | "Writing on the wire a packet having %u bytes before", currentlen); | |||
#if defined(HAVE_LIBZ) && defined(WITH_LIBZ) | #if defined(HAVE_LIBZ) && defined(WITH_LIBZ) | |||
if (session->current_crypto && session->current_crypto->do_compress_out) { | if (session->current_crypto && session->current_crypto->do_compress_out) { | |||
ssh_log(session, SSH_LOG_RARE, "Compressing in_buffer ..."); | ssh_log(session, SSH_LOG_PACKET, "Compressing in_buffer ..."); | |||
if (compress_buffer(session,session->out_buffer) < 0) { | if (compress_buffer(session,session->out_buffer) < 0) { | |||
goto error; | goto error; | |||
} | } | |||
currentlen = buffer_get_len(session->out_buffer); | currentlen = buffer_get_len(session->out_buffer); | |||
} | } | |||
#endif | #endif | |||
padding = (blocksize - ((currentlen +5) % blocksize)); | padding = (blocksize - ((currentlen +5) % blocksize)); | |||
if(padding < 4) { | if(padding < 4) { | |||
padding += blocksize; | padding += blocksize; | |||
} | } | |||
if (session->current_crypto) { | if (session->current_crypto) { | |||
ssh_get_random(padstring, padding, 0); | ssh_get_random(padstring, padding, 0); | |||
} else { | } else { | |||
memset(padstring,0,padding); | memset(padstring,0,padding); | |||
} | } | |||
finallen = htonl(currentlen + padding + 1); | finallen = htonl(currentlen + padding + 1); | |||
ssh_log(session, SSH_LOG_RARE, | ssh_log(session, SSH_LOG_PACKET, | |||
"%d bytes after comp + %d padding bytes = %lu bytes packet", | "%d bytes after comp + %d padding bytes = %lu bytes packet", | |||
currentlen, padding, (long unsigned int) ntohl(finallen)); | currentlen, padding, (long unsigned int) ntohl(finallen)); | |||
if (buffer_prepend_data(session->out_buffer, &padding, sizeof(u8)) < 0) { | if (buffer_prepend_data(session->out_buffer, &padding, sizeof(uint8_t)) < 0) { | |||
goto error; | goto error; | |||
} | } | |||
if (buffer_prepend_data(session->out_buffer, &finallen, sizeof(u32)) < 0) { | if (buffer_prepend_data(session->out_buffer, &finallen, sizeof(uint32_t)) < 0) { | |||
goto error; | goto error; | |||
} | } | |||
if (buffer_add_data(session->out_buffer, padstring, padding) < 0) { | if (buffer_add_data(session->out_buffer, padstring, padding) < 0) { | |||
goto error; | goto error; | |||
} | } | |||
#ifdef WITH_PCAP | ||||
if(session->pcap_ctx){ | ||||
ssh_pcap_context_write(session->pcap_ctx,SSH_PCAP_DIR_OUT, | ||||
buffer_get(session->out_buffer),buffer_get_len(sessi | ||||
on->out_buffer) | ||||
,buffer_get_len(session->out_buffer)); | ||||
} | ||||
#endif | ||||
hmac = packet_encrypt(session, buffer_get(session->out_buffer), | hmac = packet_encrypt(session, buffer_get(session->out_buffer), | |||
buffer_get_len(session->out_buffer)); | buffer_get_len(session->out_buffer)); | |||
if (hmac) { | if (hmac) { | |||
if (buffer_add_data(session->out_buffer, hmac, 20) < 0) { | if (buffer_add_data(session->out_buffer, hmac, 20) < 0) { | |||
goto error; | goto error; | |||
} | } | |||
} | } | |||
rc = packet_write(session); | rc = packet_write(session); | |||
session->send_seq++; | session->send_seq++; | |||
if (buffer_reinit(session->out_buffer) < 0) { | if (buffer_reinit(session->out_buffer) < 0) { | |||
rc = SSH_ERROR; | rc = SSH_ERROR; | |||
} | } | |||
error: | error: | |||
leave_function(); | leave_function(); | |||
return rc; /* SSH_OK, AGAIN or ERROR */ | return rc; /* SSH_OK, AGAIN or ERROR */ | |||
} | } | |||
#ifdef HAVE_SSH1 | #ifdef WITH_SSH1 | |||
static int packet_send1(SSH_SESSION *session) { | static int packet_send1(ssh_session session) { | |||
unsigned int blocksize = (session->current_crypto ? | unsigned int blocksize = (session->current_crypto ? | |||
session->current_crypto->out_cipher->blocksize : 8); | session->current_crypto->out_cipher->blocksize : 8); | |||
u32 currentlen = buffer_get_len(session->out_buffer) + sizeof(u32); | uint32_t currentlen = buffer_get_len(session->out_buffer) + sizeof(uint32 _t); | |||
char padstring[32] = {0}; | char padstring[32] = {0}; | |||
int rc = SSH_ERROR; | int rc = SSH_ERROR; | |||
u32 finallen; | uint32_t finallen; | |||
u32 crc; | uint32_t crc; | |||
u8 padding; | uint8_t padding; | |||
enter_function(); | enter_function(); | |||
ssh_log(session,SSH_LOG_PACKET,"Sending a %d bytes long packet",currentle n); | ssh_log(session,SSH_LOG_PACKET,"Sending a %d bytes long packet",currentle n); | |||
/* TODO FIXME | /* TODO FIXME | |||
#if defined(HAVE_LIBZ) && defined(WITH_LIBZ) | #if defined(HAVE_LIBZ) && defined(WITH_LIBZ) | |||
if (session->current_crypto && session->current_crypto->do_compress_out) { | if (session->current_crypto && session->current_crypto->do_compress_out) { | |||
if (compress_buffer(session, session->out_buffer) < 0) { | if (compress_buffer(session, session->out_buffer) < 0) { | |||
goto error; | goto error; | |||
} | } | |||
skipping to change at line 543 | skipping to change at line 575 | |||
} | } | |||
finallen = htonl(currentlen); | finallen = htonl(currentlen); | |||
ssh_log(session, SSH_LOG_PACKET, | ssh_log(session, SSH_LOG_PACKET, | |||
"%d bytes after comp + %d padding bytes = %d bytes packet", | "%d bytes after comp + %d padding bytes = %d bytes packet", | |||
currentlen, padding, ntohl(finallen)); | currentlen, padding, ntohl(finallen)); | |||
if (buffer_prepend_data(session->out_buffer, &padstring, padding) < 0) { | if (buffer_prepend_data(session->out_buffer, &padstring, padding) < 0) { | |||
goto error; | goto error; | |||
} | } | |||
if (buffer_prepend_data(session->out_buffer, &finallen, sizeof(u32)) < 0) { | if (buffer_prepend_data(session->out_buffer, &finallen, sizeof(uint32_t)) < 0) { | |||
goto error; | goto error; | |||
} | } | |||
crc = ssh_crc32(buffer_get(session->out_buffer) + sizeof(u32), | crc = ssh_crc32((char *)buffer_get(session->out_buffer) + sizeof(uint32_t | |||
buffer_get_len(session->out_buffer) - sizeof(u32)); | ), | |||
buffer_get_len(session->out_buffer) - sizeof(uint32_t)); | ||||
if (buffer_add_u32(session->out_buffer, ntohl(crc)) < 0) { | if (buffer_add_u32(session->out_buffer, ntohl(crc)) < 0) { | |||
goto error; | goto error; | |||
} | } | |||
#ifdef DEBUG_CRYPTO | #ifdef DEBUG_CRYPTO | |||
ssh_print_hexa("Clear packet", buffer_get(session->out_buffer), | ssh_print_hexa("Clear packet", buffer_get(session->out_buffer), | |||
buffer_get_len(session->out_buffer)); | buffer_get_len(session->out_buffer)); | |||
#endif | #endif | |||
packet_encrypt(session, buffer_get(session->out_buffer) + sizeof(u32), | packet_encrypt(session, (unsigned char *)buffer_get(session->out_buffer) | |||
buffer_get_len(session->out_buffer) - sizeof(u32)); | + sizeof(uint32_t), | |||
buffer_get_len(session->out_buffer) - sizeof(uint32_t)); | ||||
#ifdef DEBUG_CRYPTO | #ifdef DEBUG_CRYPTO | |||
ssh_print_hexa("encrypted packet",buffer_get(session->out_buffer), | ssh_print_hexa("encrypted packet",buffer_get(session->out_buffer), | |||
buffer_get_len(session->out_buffer)); | buffer_get_len(session->out_buffer)); | |||
#endif | #endif | |||
if (ssh_socket_write(session->socket, buffer_get(session->out_buffer), | if (ssh_socket_write(session->socket, buffer_get(session->out_buffer), | |||
buffer_get_len(session->out_buffer)) == SSH_ERROR) { | buffer_get_len(session->out_buffer)) == SSH_ERROR) { | |||
goto error; | goto error; | |||
} | } | |||
skipping to change at line 584 | skipping to change at line 616 | |||
if (buffer_reinit(session->out_buffer) < 0) { | if (buffer_reinit(session->out_buffer) < 0) { | |||
rc = SSH_ERROR; | rc = SSH_ERROR; | |||
} | } | |||
error: | error: | |||
leave_function(); | leave_function(); | |||
return rc; /* SSH_OK, AGAIN or ERROR */ | return rc; /* SSH_OK, AGAIN or ERROR */ | |||
} | } | |||
#endif /* WITH_SSH1 */ | #endif /* WITH_SSH1 */ | |||
int packet_send(SSH_SESSION *session) { | int packet_send(ssh_session session) { | |||
#ifdef HAVE_SSH1 | #ifdef WITH_SSH1 | |||
if (session->version == 1) { | if (session->version == 1) { | |||
return packet_send1(session); | return packet_send1(session); | |||
} | } | |||
#endif | #endif | |||
return packet_send2(session); | return packet_send2(session); | |||
} | } | |||
void packet_parse(SSH_SESSION *session) { | void packet_parse(ssh_session session) { | |||
STRING *error_s = NULL; | ssh_string error_s = NULL; | |||
char *error = NULL; | char *error = NULL; | |||
int type = session->in_packet.type; | uint32_t type = session->in_packet.type; | |||
u32 tmp; | uint32_t tmp; | |||
#ifdef WITH_SSH1 | #ifdef WITH_SSH1 | |||
if (session->version == 1) { | if (session->version == 1) { | |||
/* SSH-1 */ | /* SSH-1 */ | |||
switch(type) { | switch(type) { | |||
case SSH_MSG_DISCONNECT: | case SSH_MSG_DISCONNECT: | |||
ssh_log(session, SSH_LOG_PACKET, "Received SSH_MSG_DISCONNECT"); | ssh_log(session, SSH_LOG_PACKET, "Received SSH_MSG_DISCONNECT"); | |||
ssh_set_error(session, SSH_FATAL, "Received SSH_MSG_DISCONNECT"); | ssh_set_error(session, SSH_FATAL, "Received SSH_MSG_DISCONNECT"); | |||
ssh_socket_close(session->socket); | ssh_socket_close(session->socket); | |||
skipping to change at line 654 | skipping to change at line 686 | |||
session->alive = 0; | session->alive = 0; | |||
return; | return; | |||
case SSH2_MSG_CHANNEL_WINDOW_ADJUST: | case SSH2_MSG_CHANNEL_WINDOW_ADJUST: | |||
case SSH2_MSG_CHANNEL_DATA: | case SSH2_MSG_CHANNEL_DATA: | |||
case SSH2_MSG_CHANNEL_EXTENDED_DATA: | case SSH2_MSG_CHANNEL_EXTENDED_DATA: | |||
case SSH2_MSG_CHANNEL_REQUEST: | case SSH2_MSG_CHANNEL_REQUEST: | |||
case SSH2_MSG_CHANNEL_EOF: | case SSH2_MSG_CHANNEL_EOF: | |||
case SSH2_MSG_CHANNEL_CLOSE: | case SSH2_MSG_CHANNEL_CLOSE: | |||
channel_handle(session,type); | channel_handle(session,type); | |||
return; | ||||
case SSH2_MSG_IGNORE: | case SSH2_MSG_IGNORE: | |||
case SSH2_MSG_DEBUG: | case SSH2_MSG_DEBUG: | |||
return; | return; | |||
case SSH2_MSG_SERVICE_REQUEST: | ||||
case SSH2_MSG_USERAUTH_REQUEST: | ||||
case SSH2_MSG_CHANNEL_OPEN: | ||||
message_handle(session,type); | ||||
return; | ||||
default: | default: | |||
ssh_log(session, SSH_LOG_RARE, "Received unhandled packet %d", type ); | ssh_log(session, SSH_LOG_RARE, "Received unhandled packet %d", type ); | |||
} | } | |||
#ifdef WITH_SSH1 | #ifdef WITH_SSH1 | |||
} | } | |||
#endif | #endif | |||
} | } | |||
#ifdef WITH_SSH1 | #ifdef WITH_SSH1 | |||
static int packet_wait1(SSH_SESSION *session, int type, int blocking) { | static int packet_wait1(ssh_session session, int type, int blocking) { | |||
enter_function(); | enter_function(); | |||
ssh_log(session, SSH_LOG_PROTOCOL, "packet_wait1 waiting for %d", type); | ssh_log(session, SSH_LOG_PROTOCOL, "packet_wait1 waiting for %d", type); | |||
do { | do { | |||
if ((packet_read1(session) != SSH_OK) || | if ((packet_read1(session) != SSH_OK) || | |||
(packet_translate(session) != SSH_OK)) { | (packet_translate(session) != SSH_OK)) { | |||
leave_function(); | leave_function(); | |||
return SSH_ERROR; | return SSH_ERROR; | |||
skipping to change at line 723 | skipping to change at line 761 | |||
leave_function(); | leave_function(); | |||
return SSH_OK; | return SSH_OK; | |||
} | } | |||
} while(1); | } while(1); | |||
leave_function(); | leave_function(); | |||
return SSH_OK; | return SSH_OK; | |||
} | } | |||
#endif /* WITH_SSH1 */ | #endif /* WITH_SSH1 */ | |||
static int packet_wait2(SSH_SESSION *session, int type, int blocking) { | static int packet_wait2(ssh_session session, int type, int blocking) { | |||
int rc = SSH_ERROR; | int rc = SSH_ERROR; | |||
enter_function(); | enter_function(); | |||
do { | do { | |||
rc = packet_read2(session); | rc = packet_read2(session); | |||
if (rc != SSH_OK) { | if (rc != SSH_OK) { | |||
leave_function(); | leave_function(); | |||
return rc; | return rc; | |||
} | } | |||
if (packet_translate(session) != SSH_OK) { | if (packet_translate(session) != SSH_OK) { | |||
skipping to change at line 749 | skipping to change at line 787 | |||
packet_parse(session); | packet_parse(session); | |||
ssh_log(session, SSH_LOG_PACKET, "received disconnect packet"); | ssh_log(session, SSH_LOG_PACKET, "received disconnect packet"); | |||
leave_function(); | leave_function(); | |||
return SSH_ERROR; | return SSH_ERROR; | |||
case SSH2_MSG_CHANNEL_WINDOW_ADJUST: | case SSH2_MSG_CHANNEL_WINDOW_ADJUST: | |||
case SSH2_MSG_CHANNEL_DATA: | case SSH2_MSG_CHANNEL_DATA: | |||
case SSH2_MSG_CHANNEL_EXTENDED_DATA: | case SSH2_MSG_CHANNEL_EXTENDED_DATA: | |||
case SSH2_MSG_CHANNEL_REQUEST: | case SSH2_MSG_CHANNEL_REQUEST: | |||
case SSH2_MSG_CHANNEL_EOF: | case SSH2_MSG_CHANNEL_EOF: | |||
case SSH2_MSG_CHANNEL_CLOSE: | case SSH2_MSG_CHANNEL_CLOSE: | |||
case SSH2_MSG_SERVICE_REQUEST: | ||||
case SSH2_MSG_USERAUTH_REQUEST: | ||||
case SSH2_MSG_CHANNEL_OPEN: | ||||
packet_parse(session); | packet_parse(session); | |||
break; | break; | |||
case SSH2_MSG_IGNORE: | case SSH2_MSG_IGNORE: | |||
case SSH2_MSG_DEBUG: | ||||
break; | break; | |||
default: | default: | |||
if (type && (type != session->in_packet.type)) { | if (type && (type != session->in_packet.type)) { | |||
ssh_set_error(session, SSH_FATAL, | ssh_set_error(session, SSH_FATAL, | |||
"packet_wait2(): Received a %d type packet, but expected a %d \n", | "packet_wait2(): Received a %d type packet, but expected a %d \n", | |||
session->in_packet.type, type); | session->in_packet.type, type); | |||
leave_function(); | leave_function(); | |||
return SSH_ERROR; | return SSH_ERROR; | |||
} | } | |||
leave_function(); | leave_function(); | |||
skipping to change at line 774 | skipping to change at line 816 | |||
if (blocking == 0) { | if (blocking == 0) { | |||
leave_function(); | leave_function(); | |||
return SSH_OK; //shouldn't it return SSH_AGAIN here ? | return SSH_OK; //shouldn't it return SSH_AGAIN here ? | |||
} | } | |||
} while(1); | } while(1); | |||
leave_function(); | leave_function(); | |||
return SSH_OK; | return SSH_OK; | |||
} | } | |||
int packet_wait(SSH_SESSION *session, int type, int block) { | int packet_wait(ssh_session session, int type, int block) { | |||
#ifdef WITH_SSH1 | #ifdef WITH_SSH1 | |||
if (session->version == 1) { | if (session->version == 1) { | |||
return packet_wait1(session, type, block); | return packet_wait1(session, type, block); | |||
} | } | |||
#endif | #endif | |||
return packet_wait2(session, type, block); | return packet_wait2(session, type, block); | |||
} | } | |||
/* vim: set ts=2 sw=2 et cindent: */ | /* vim: set ts=2 sw=2 et cindent: */ | |||
End of changes. 54 change blocks. | ||||
62 lines changed or deleted | 110 lines changed or added | |||
This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/ |