aboutsummaryrefslogtreecommitdiff
path: root/libssh/packet.c
diff options
context:
space:
mode:
Diffstat (limited to 'libssh/packet.c')
-rw-r--r--libssh/packet.c529
1 files changed, 0 insertions, 529 deletions
diff --git a/libssh/packet.c b/libssh/packet.c
deleted file mode 100644
index a97db93b..00000000
--- a/libssh/packet.c
+++ /dev/null
@@ -1,529 +0,0 @@
-/*
- * packet.c - packet building functions
- *
- * This file is part of the SSH Library
- *
- * Copyright (c) 2003-2008 by Aris Adamantiadis
- *
- * The SSH Library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or (at your
- * option) any later version.
- *
- * The SSH Library is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
- * License for more details.
- *
- * 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
- * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
- * MA 02111-1307, USA.
- */
-
-#include "config.h"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-
-#ifndef _WIN32
-#include <arpa/inet.h>
-#endif
-
-#include "libssh/priv.h"
-#include "libssh/ssh2.h"
-#include "libssh/crypto.h"
-#include "libssh/buffer.h"
-#include "libssh/packet.h"
-#include "libssh/socket.h"
-#include "libssh/channels.h"
-#include "libssh/misc.h"
-#include "libssh/session.h"
-#include "libssh/messages.h"
-#include "libssh/pcap.h"
-#include "libssh/kex.h"
-#include "libssh/auth.h"
-
-ssh_packet_callback default_packet_handlers[]= {
- ssh_packet_disconnect_callback, // SSH2_MSG_DISCONNECT 1
- ssh_packet_ignore_callback, // SSH2_MSG_IGNORE 2
- ssh_packet_unimplemented, // SSH2_MSG_UNIMPLEMENTED 3
- ssh_packet_ignore_callback, // SSH2_MSG_DEBUG 4
- ssh_packet_service_request, // SSH2_MSG_SERVICE_REQUEST 5
- ssh_packet_service_accept, // SSH2_MSG_SERVICE_ACCEPT 6
- NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, // 7-19
- ssh_packet_kexinit, // SSH2_MSG_KEXINIT 20
- ssh_packet_newkeys, // SSH2_MSG_NEWKEYS 21
- NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, // 22-29
-#if WITH_SERVER
- ssh_packet_kexdh_init, // SSH2_MSG_KEXDH_INIT 30
- // SSH2_MSG_KEX_DH_GEX_REQUEST_OLD 30
-#else
- NULL,
-#endif
- ssh_packet_dh_reply, // SSH2_MSG_KEXDH_REPLY 31
- // SSH2_MSG_KEX_DH_GEX_GROUP 31
- NULL, // SSH2_MSG_KEX_DH_GEX_INIT 32
- NULL, // SSH2_MSG_KEX_DH_GEX_REPLY 33
- NULL, // SSH2_MSG_KEX_DH_GEX_REQUEST 34
- NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, // 35-49
- ssh_packet_userauth_request, // SSH2_MSG_USERAUTH_REQUEST 50
- ssh_packet_userauth_failure, // SSH2_MSG_USERAUTH_FAILURE 51
- ssh_packet_userauth_success, // SSH2_MSG_USERAUTH_SUCCESS 52
- ssh_packet_userauth_banner, // SSH2_MSG_USERAUTH_BANNER 53
- NULL,NULL,NULL,NULL,NULL,NULL, // 54-59
- ssh_packet_userauth_pk_ok, // SSH2_MSG_USERAUTH_PK_OK 60
- // SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ 60
- // SSH2_MSG_USERAUTH_INFO_REQUEST 60
- NULL, // SSH2_MSG_USERAUTH_INFO_RESPONSE 61
- NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, // 62-79
- NULL, // SSH2_MSG_GLOBAL_REQUEST 80
- ssh_request_success, // SSH2_MSG_REQUEST_SUCCESS 81
- ssh_request_denied, // SSH2_MSG_REQUEST_FAILURE 82
- NULL, NULL, NULL, NULL, NULL, NULL, NULL,// 83-89
- ssh_packet_channel_open, // SSH2_MSG_CHANNEL_OPEN 90
- ssh_packet_channel_open_conf, // SSH2_MSG_CHANNEL_OPEN_CONFIRMATION 91
- ssh_packet_channel_open_fail, // SSH2_MSG_CHANNEL_OPEN_FAILURE 92
- channel_rcv_change_window, // SSH2_MSG_CHANNEL_WINDOW_ADJUST 93
- channel_rcv_data, // SSH2_MSG_CHANNEL_DATA 94
- channel_rcv_data, // SSH2_MSG_CHANNEL_EXTENDED_DATA 95
- channel_rcv_eof, // SSH2_MSG_CHANNEL_EOF 96
- channel_rcv_close, // SSH2_MSG_CHANNEL_CLOSE 97
- channel_rcv_request, // SSH2_MSG_CHANNEL_REQUEST 98
- ssh_packet_channel_success, // SSH2_MSG_CHANNEL_SUCCESS 99
- ssh_packet_channel_failure, // SSH2_MSG_CHANNEL_FAILURE 100
-};
-
-/* XXX include selected mac size */
-static int macsize=SHA_DIGEST_LEN;
-
-/* 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. */
-
-/** @internal
- * @handles a data received event. It then calls the handlers for the different packet types
- * or and exception handler callback.
- * @param user pointer to current ssh_session
- * @param data pointer to the data received
- * @len length of data received. It might not be enough for a complete packet
- * @returns number of bytes read and processed.
- */
-int ssh_packet_socket_callback(const void *data, size_t receivedlen, void *user){
- ssh_session session=(ssh_session) user;
- unsigned int blocksize = (session->current_crypto ?
- session->current_crypto->in_cipher->blocksize : 8);
- int current_macsize = session->current_crypto ? macsize : 0;
- unsigned char mac[30] = {0};
- char buffer[16] = {0};
- void *packet=NULL;
- int to_be_read;
- int rc;
- uint32_t len;
- uint8_t padding;
- size_t processed=0; /* number of byte processed from the callback */
-
- enter_function();
-
- switch(session->packet_state) {
- case PACKET_STATE_INIT:
- if(receivedlen < blocksize){
- /* We didn't receive enough data to read at least one block size, give up */
- leave_function();
- return 0;
- }
- memset(&session->in_packet, 0, sizeof(PACKET));
-
- if (session->in_buffer) {
- if (buffer_reinit(session->in_buffer) < 0) {
- goto error;
- }
- } else {
- session->in_buffer = ssh_buffer_new();
- if (session->in_buffer == NULL) {
- goto error;
- }
- }
-
- memcpy(buffer,data,blocksize);
- processed += blocksize;
- len = packet_decrypt_len(session, buffer);
-
- if (buffer_add_data(session->in_buffer, buffer, blocksize) < 0) {
- goto error;
- }
-
- if(len > MAX_PACKET_LEN) {
- ssh_set_error(session, SSH_FATAL,
- "read_packet(): Packet len too high(%u %.4x)", len, len);
- goto error;
- }
-
- to_be_read = len - blocksize + sizeof(uint32_t);
- if (to_be_read < 0) {
- /* remote sshd sends invalid sizes? */
- ssh_set_error(session, SSH_FATAL,
- "given numbers of bytes left to be read < 0 (%d)!", to_be_read);
- goto error;
- }
-
- /* saves the status of the current operations */
- session->in_packet.len = len;
- session->packet_state = PACKET_STATE_SIZEREAD;
- case PACKET_STATE_SIZEREAD:
- len = session->in_packet.len;
- 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 != 0) {
- if(receivedlen - processed < (unsigned int)to_be_read){
- /* give up, not enough data in buffer */
- return processed;
- }
-
- packet = (unsigned char *)data + processed;
-// ssh_socket_read(session->socket,packet,to_be_read-current_macsize);
-
- ssh_log(session,SSH_LOG_PACKET,"Read a %d bytes packet",len);
-
- if (buffer_add_data(session->in_buffer, packet,
- to_be_read - current_macsize) < 0) {
- goto error;
- }
- processed += to_be_read - current_macsize;
- }
-
- if (session->current_crypto) {
- /*
- * decrypt the rest of the packet (blocksize bytes already
- * have been decrypted)
- */
- if (packet_decrypt(session,
- ((uint8_t*)ssh_buffer_get_begin(session->in_buffer) + blocksize),
- ssh_buffer_get_len(session->in_buffer) - blocksize) < 0) {
- ssh_set_error(session, SSH_FATAL, "Decrypt error");
- goto error;
- }
- /* copy the last part from the incoming buffer */
- memcpy(mac,(unsigned char *)packet + to_be_read - current_macsize, macsize);
-
- if (packet_hmac_verify(session, session->in_buffer, mac) < 0) {
- ssh_set_error(session, SSH_FATAL, "HMAC error");
- goto error;
- }
- processed += current_macsize;
- }
-
- /* skip the size field which has been processed before */
- buffer_pass_bytes(session->in_buffer, sizeof(uint32_t));
-
- if (buffer_get_u8(session->in_buffer, &padding) == 0) {
- ssh_set_error(session, SSH_FATAL, "Packet too short to read padding");
- goto error;
- }
-
- ssh_log(session, SSH_LOG_PACKET,
- "%hhd bytes padding, %d bytes left in buffer",
- padding, buffer_get_rest_len(session->in_buffer));
-
- if (padding > buffer_get_rest_len(session->in_buffer)) {
- ssh_set_error(session, SSH_FATAL,
- "Invalid padding: %d (%d resting)",
- padding,
- buffer_get_rest_len(session->in_buffer));
-#ifdef DEBUG_CRYPTO
- ssh_print_hexa("incrimined packet",
- ssh_buffer_get_begin(session->in_buffer),
- ssh_buffer_get_len(session->in_buffer));
-#endif
- goto error;
- }
- buffer_pass_bytes_end(session->in_buffer, padding);
-
- ssh_log(session, SSH_LOG_PACKET,
- "After padding, %d bytes left in buffer",
- buffer_get_rest_len(session->in_buffer));
-#if defined(HAVE_LIBZ) && defined(WITH_LIBZ)
- if (session->current_crypto && session->current_crypto->do_compress_in) {
- ssh_log(session, SSH_LOG_PACKET, "Decompressing in_buffer ...");
- if (decompress_buffer(session, session->in_buffer,MAX_PACKET_LEN) < 0) {
- goto error;
- }
- }
-#endif
- session->recv_seq++;
- /* We don't want to rewrite a new packet while still executing the packet callbacks */
- session->packet_state = PACKET_STATE_PROCESSING;
- ssh_packet_parse_type(session);
- /* execute callbacks */
- ssh_packet_process(session, session->in_packet.type);
- session->packet_state = PACKET_STATE_INIT;
- if(processed < receivedlen){
- /* Handle a potential packet left in socket buffer */
- ssh_log(session,SSH_LOG_PACKET,"Processing %" PRIdS " bytes left in socket buffer",
- receivedlen-processed);
- rc = ssh_packet_socket_callback((char *)data + processed,
- receivedlen - processed,user);
- processed += rc;
- }
- leave_function();
- return processed;
- case PACKET_STATE_PROCESSING:
- ssh_log(session, SSH_LOG_RARE, "Nested packet processing. Delaying.");
- return 0;
- }
-
- ssh_set_error(session, SSH_FATAL,
- "Invalid state into packet_read2(): %d",
- session->packet_state);
-
-error:
- leave_function();
- return processed;
-}
-
-void ssh_packet_register_socket_callback(ssh_session session, ssh_socket s){
- session->socket_callbacks.data=ssh_packet_socket_callback;
- session->socket_callbacks.connected=NULL;
- session->socket_callbacks.controlflow=NULL;
- session->socket_callbacks.exception=NULL;
- session->socket_callbacks.userdata=session;
- ssh_socket_set_callbacks(s,&session->socket_callbacks);
-}
-
-/** @internal
- * @brief sets the callbacks for the packet layer
- */
-void ssh_packet_set_callbacks(ssh_session session, ssh_packet_callbacks callbacks){
- if(session->packet_callbacks == NULL){
- session->packet_callbacks = ssh_list_new();
- }
- ssh_list_append(session->packet_callbacks, callbacks);
-}
-
-/** @internal
- * @brief sets the default packet handlers
- */
-void ssh_packet_set_default_callbacks(ssh_session session){
-#ifdef WITH_SSH1
- if(session->version==1){
- ssh_packet_set_default_callbacks1(session);
- return;
- }
-#endif
- session->default_packet_callbacks.start=1;
- session->default_packet_callbacks.n_callbacks=sizeof(default_packet_handlers)/sizeof(ssh_packet_callback);
- session->default_packet_callbacks.user=session;
- session->default_packet_callbacks.callbacks=default_packet_handlers;
- ssh_packet_set_callbacks(session, &session->default_packet_callbacks);
-}
-
-/** @internal
- * @brief dispatch the call of packet handlers callbacks for a received packet
- * @param type type of packet
- */
-void ssh_packet_process(ssh_session session, uint8_t type){
- struct ssh_iterator *i;
- int r=SSH_PACKET_NOT_USED;
- ssh_packet_callbacks cb;
- enter_function();
- ssh_log(session,SSH_LOG_PACKET, "Dispatching handler for packet type %d",type);
- if(session->packet_callbacks == NULL){
- ssh_log(session,SSH_LOG_RARE,"Packet callback is not initialized !");
- goto error;
- }
- i=ssh_list_get_iterator(session->packet_callbacks);
- while(i != NULL){
- cb=ssh_iterator_value(ssh_packet_callbacks,i);
- i=i->next;
- if(!cb)
- continue;
- if(cb->start > type)
- continue;
- if(cb->start + cb->n_callbacks <= type)
- continue;
- if(cb->callbacks[type - cb->start]==NULL)
- continue;
- r=cb->callbacks[type - cb->start](session,type,session->in_buffer,cb->user);
- if(r==SSH_PACKET_USED)
- break;
- }
- if(r==SSH_PACKET_NOT_USED){
- ssh_log(session,SSH_LOG_RARE,"Couldn't do anything with packet type %d",type);
- ssh_packet_send_unimplemented(session, session->recv_seq-1);
- }
-error:
- leave_function();
-}
-
-/** @internal
- * @brief sends a SSH_MSG_UNIMPLEMENTED answer to an unhandled packet
- * @param session the SSH session
- * @param seqnum the sequence number of the unknown packet
- * @return SSH_ERROR on error, else SSH_OK
- */
-int ssh_packet_send_unimplemented(ssh_session session, uint32_t seqnum){
- int r;
- enter_function();
- buffer_add_u8(session->out_buffer, SSH2_MSG_UNIMPLEMENTED);
- buffer_add_u32(session->out_buffer, htonl(seqnum));
- r = packet_send(session);
- leave_function();
- return r;
-}
-
-/** @internal
- * @brief handles a SSH_MSG_UNIMPLEMENTED packet
- */
-SSH_PACKET_CALLBACK(ssh_packet_unimplemented){
- uint32_t seq;
- (void)type;
- (void)user;
- buffer_get_u32(packet,&seq);
- seq=ntohl(seq);
- ssh_log(session,SSH_LOG_RARE,
- "Received SSH_MSG_UNIMPLEMENTED (sequence number %d)",seq);
- return SSH_PACKET_USED;
-}
-
-/** @internal
- * @parse the "Type" header field of a packet and updates the session
- */
-int ssh_packet_parse_type(ssh_session session) {
- enter_function();
-
- memset(&session->in_packet, 0, sizeof(PACKET));
- if(session->in_buffer == NULL) {
- leave_function();
- return SSH_ERROR;
- }
-
- ssh_log(session, SSH_LOG_PACKET, "Final size %d",
- buffer_get_rest_len(session->in_buffer));
-
- if(buffer_get_u8(session->in_buffer, &session->in_packet.type) == 0) {
- ssh_set_error(session, SSH_FATAL, "Packet too short to read type");
- leave_function();
- return SSH_ERROR;
- }
-
- ssh_log(session, SSH_LOG_PACKET, "Type %hhd", session->in_packet.type);
- session->in_packet.valid = 1;
-
- leave_function();
- return SSH_OK;
-}
-
-/*
- * This function places the outgoing packet buffer into an outgoing
- * socket buffer
- */
-static int ssh_packet_write(ssh_session session) {
- int rc = SSH_ERROR;
-
- enter_function();
-
- rc=ssh_socket_write(session->socket,
- ssh_buffer_get_begin(session->out_buffer),
- ssh_buffer_get_len(session->out_buffer));
- if(rc == SSH_OK){
- rc=ssh_socket_nonblocking_flush(session->socket);
- }
- leave_function();
- return rc;
-}
-
-static int packet_send2(ssh_session session) {
- unsigned int blocksize = (session->current_crypto ?
- session->current_crypto->out_cipher->blocksize : 8);
- uint32_t currentlen = ssh_buffer_get_len(session->out_buffer);
- unsigned char *hmac = NULL;
- char padstring[32] = {0};
- int rc = SSH_ERROR;
- uint32_t finallen;
- uint8_t padding;
-
- enter_function();
-
- ssh_log(session, SSH_LOG_PACKET,
- "Writing on the wire a packet having %u bytes before", currentlen);
-
-#if defined(HAVE_LIBZ) && defined(WITH_LIBZ)
- if (session->current_crypto && session->current_crypto->do_compress_out) {
- ssh_log(session, SSH_LOG_PACKET, "Compressing in_buffer ...");
- if (compress_buffer(session,session->out_buffer) < 0) {
- goto error;
- }
- currentlen = ssh_buffer_get_len(session->out_buffer);
- }
-#endif
- padding = (blocksize - ((currentlen +5) % blocksize));
- if(padding < 4) {
- padding += blocksize;
- }
-
- if (session->current_crypto) {
- ssh_get_random(padstring, padding, 0);
- } else {
- memset(padstring,0,padding);
- }
-
- finallen = htonl(currentlen + padding + 1);
- ssh_log(session, SSH_LOG_PACKET,
- "%d bytes after comp + %d padding bytes = %lu bytes packet",
- currentlen, padding, (long unsigned int) ntohl(finallen));
-
- if (buffer_prepend_data(session->out_buffer, &padding, sizeof(uint8_t)) < 0) {
- goto error;
- }
- if (buffer_prepend_data(session->out_buffer, &finallen, sizeof(uint32_t)) < 0) {
- goto error;
- }
- if (buffer_add_data(session->out_buffer, padstring, padding) < 0) {
- goto error;
- }
-#ifdef WITH_PCAP
- if(session->pcap_ctx){
- ssh_pcap_context_write(session->pcap_ctx,SSH_PCAP_DIR_OUT,
- ssh_buffer_get_begin(session->out_buffer),ssh_buffer_get_len(session->out_buffer)
- ,ssh_buffer_get_len(session->out_buffer));
- }
-#endif
- hmac = packet_encrypt(session, ssh_buffer_get_begin(session->out_buffer),
- ssh_buffer_get_len(session->out_buffer));
- if (hmac) {
- if (buffer_add_data(session->out_buffer, hmac, 20) < 0) {
- goto error;
- }
- }
-
- rc = ssh_packet_write(session);
- session->send_seq++;
-
- if (buffer_reinit(session->out_buffer) < 0) {
- rc = SSH_ERROR;
- }
-error:
- leave_function();
- return rc; /* SSH_OK, AGAIN or ERROR */
-}
-
-
-int packet_send(ssh_session session) {
-#ifdef WITH_SSH1
- if (session->version == 1) {
- return packet_send1(session);
- }
-#endif
- return packet_send2(session);
-}
-
-
-/* vim: set ts=2 sw=2 et cindent: */