Files
m241Neelima/components/ip_net2-6.9/ipssh/src/ipssh_connection_v1.c
T
2026-07-30 11:19:44 +05:30

1092 lines
30 KiB
C

/*
******************************************************************************
* SOURCE FILE
*
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipssh_connection_v1.c,v $ $Revision: 1.64.10.3 $
* $Source: /home/interpeak/CVSRoot/ipssh/src/ipssh_connection_v1.c,v $
* $Author: jren $
* $State: Exp $ $Locker: $
*
* INTERPEAK_COPYRIGHT_STRING
* Design and implementation by Roger Boden <roger@interpeak.se>
******************************************************************************
*/
/*
****************************************************************************
* 1 DESCRIPTION
****************************************************************************
*/
/*
****************************************************************************
* 2 CONFIGURATION
****************************************************************************
*/
#include <ipssh_config.h>
#ifdef IPSSH_USE_V1
/*
****************************************************************************
* 3 INCLUDE FILES
****************************************************************************
*/
#include "ipssh_h.h"
#include "ipssh_buffer.h"
#include "ipssh_channel.h"
#include "ipssh_transport_v1.h"
#include "ipssh_connection_v1.h"
#include "ipssh_connection.h"
#include <ipcom_clib.h>
#include <ipcom_cstyle.h>
#include <ipcom_type.h>
#include <ipcom_sock.h>
#include <ipcom_err.h>
/*
****************************************************************************
* 4 DEFINES
****************************************************************************
*/
#define IPSSH_PORT_FWD_CHUNK 2048
/*
****************************************************************************
* 5 TYPES
****************************************************************************
*/
/*
****************************************************************************
* 6 EXTERN PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 7 LOCAL PROTOTYPES
****************************************************************************
*/
/*
****************************************************************************
* 8 DATA
****************************************************************************
*/
/*
****************************************************************************
* 9 LOCAL FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipssh_lookup_port_fwd_addr
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ip_err
ipssh_lookup_port_fwd_addr(Ipcom_list* map, Ip_fd sock, char** addr, Ip_u32* port)
{
Ipcom_list* current;
for(current = ipcom_list_first(map); current; current = ipcom_list_next(current))
{
Ipssh_port_fwd_addr_map* entry = (Ipssh_port_fwd_addr_map*) current;
if(entry->sock == sock)
{
*addr = entry->addr;
*port = entry->port;
return IPCOM_SUCCESS;
}
}
return IPCOM_ERR_FAILED;
}
/*
*===========================================================================
* ipssh_store_port_fwd_addr
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ip_err
ipssh_store_port_fwd_addr(Ipcom_list* map, Ip_fd sock, const char* addr, const Ip_u32 port)
{
Ipssh_port_fwd_addr_map* entry;
entry = ipcom_malloc(sizeof(Ipssh_port_fwd_addr_map));
if(!entry)
return IPCOM_ERR_FAILED;
entry->addr = ipcom_malloc(ipcom_strlen(addr)+1);
if(!entry->addr)
{
ipcom_free(entry);
return IPCOM_ERR_FAILED;
}
ipcom_strcpy(entry->addr, addr);
entry->port = port;
entry->sock = sock;
ipcom_list_insert_last(map, (Ipcom_list*) entry);
return IPCOM_SUCCESS;
}
/*
*===========================================================================
* ipssh_port_fwd_listen_handler_v1
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL Ip_err
ipssh_port_fwd_listen_handler_v1(Ip_fd sock, Ipssh_conn_ctx* ctx, Ipssh_map_entry* map_entry)
{
Ip_fd clt_sock;
Ipssh_channel* channel;
Ipcom_buffer* pkt;
char* conn_addr;
Ip_u32 conn_port;
(void) map_entry;
clt_sock = ipcom_accept(sock, IP_NULL, IP_NULL);
if(clt_sock == IP_INVALID_SOCKET)
{
IPCOM_LOG1(ERR, "ipssh_port_fwd_listen_handler_v1 :: ipcom_accept() failed, errno=%d", ipcom_errno);
return IPCOM_SUCCESS;
}
channel = ipssh_channel_new(ctx->ssh_conn, 0xffffffff, ipssh_channel2sock_handler);
if(!channel)
{
IPCOM_LOG0(ERR, "ipssh_port_fwd_listen_handler_v1 :: ipssh_channel_new failed");
ipcom_socketclose(clt_sock);
return IPCOM_SUCCESS;
}
channel->data.port_fwd.sock = clt_sock;
channel->type = IPSSH_CH_TYPE_PORT_FWD;
if(ipssh_lookup_port_fwd_addr(&(ctx->ssh_conn->port_fwd_addr_map), sock, &conn_addr, &conn_port) != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipssh_port_fwd_listen_handler_v1 :: no connect addr for port forward socket");
ipcom_socketclose(clt_sock);
return IPCOM_ERR_FAILED;
}
pkt = ipssh_buffer_new_v1_pkt(256, IPSSH_MSG_V1_PORT_OPEN);
if(!pkt)
{
IPCOM_LOG0(ERR, "ipssh_port_fwd_listen_handler_v1 :: out of memory");
ipcom_socketclose(clt_sock);
return IPCOM_ERR_FAILED;
}
/* Open channel to convey forwarded tcp connection */
if( ipcom_buffer_put_int(pkt, ip_htonl(channel->my_ch_id)) ||
ipssh_buffer_put_sshstr(pkt, conn_addr) ||
ipcom_buffer_put_int(pkt, ip_htonl(conn_port)) )
{
IPCOM_LOG0(ERR, "ipssh_port_fwd_listen_handler_v1 :: failed to pack message");
ipcom_buffer_free(pkt);
return IPCOM_ERR_FAILED;
}
if(ipssh_send_v1_pkt(ctx->ssh_conn, pkt) != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipssh_port_fwd_listen_handler_v1 :: failed to send message");
return IPCOM_ERR_FAILED;
}
return IPCOM_SUCCESS;
}
/*
*===========================================================================
* ipssh_parse_terminal_modes_v1
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_STATIC Ip_err
ipssh_parse_terminal_modes_v1(Ipcom_buffer* pkt, Ipssh_term_modes* term_modes)
{
Ip_u8 mode;
Ip_u8 small_value;
Ip_u32 big_value;
while(ipcom_buffer_len(pkt) > 0)
{
(void)ipcom_buffer_get_char(pkt, &mode);
if(mode == IPSSH_TTY_OP_END)
break;
if(mode < 128)
{
if(ipcom_buffer_get_char(pkt, &small_value))
return IPCOM_ERR_FAILED;
}
else
{
if(ipssh_buffer_get_uint(pkt, &big_value))
return IPCOM_ERR_FAILED;
}
switch(mode)
{
case IPSSH_ONLCR:
term_modes->ONLCR = small_value; /*lint !e644*/
break;
default:
/* NOP */
break;
}
}
return IPCOM_SUCCESS;
}
/*
*===========================================================================
* ipssh_v1_setup_stdio_channel
*===========================================================================
* Description:
* In SSH v1 no channel is used to convey stdio data. Instead dedicated messages
* are used. However, we create a channel struct to hold terminal session
* data anyway
*
* Parameters:
* Returns:
*
*/
IP_STATIC Ip_err
ipssh_v1_setup_stdio_channel(Ipssh_conn* ssh_conn)
{
ssh_conn->stdio_channel = ipssh_channel_new(ssh_conn, 0xffffffff, IP_NULL);
if(!ssh_conn->stdio_channel)
{
IPCOM_LOG0(ERR, "ipssh_v1_setup_stdio_channel :: ipssh_channel_new() failed");
return IPCOM_ERR_FAILED;
}
ssh_conn->stdio_channel->type = IPSSH_CH_TYPE_SHELL;
ipssh_set_default_term_modes(&ssh_conn->stdio_channel->data.shell.term_modes);
return IPCOM_SUCCESS;
}
/*
****************************************************************************
* 10 PUBLIC FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipssh_v1_msg_exec_cmd
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL Ip_err
ipssh_v1_msg_exec_cmd(Ipssh_conn* ssh_conn, Ipcom_buffer* pkt)
{
Ip_err rc;
char* cmd;
if (!ssh_conn->stdio_channel && ipssh_v1_setup_stdio_channel(ssh_conn) != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipssh_v1_msg_exec_cmd :: ipssh_v1_setup_stdio_channel() failed");
return IPCOM_ERR_FAILED;
}
ssh_conn->conn_state = IPSSH_CONN_STATE_SRV_TERM;
cmd = ipssh_buffer_get_sshstr(pkt);
if (!cmd)
{
IPCOM_LOG0(ERR, "ipssh_v1_msg_exec_cmd :: failed to unpack cmd");
return IPCOM_ERR_FAILED;
}
rc = ipssh_handle_exec_cmd(ssh_conn, ssh_conn->stdio_channel, cmd);
ipcom_free(cmd);
return rc;
}
/*
*===========================================================================
* ipssh_v1_msg_exec_shell
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL Ip_err
ipssh_v1_msg_exec_shell(Ipssh_conn* ssh_conn, Ipcom_buffer* pkt)
{
(void) pkt;
if (!ssh_conn->stdio_channel && ipssh_v1_setup_stdio_channel(ssh_conn) != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipssh_v1_msg_exec_shell :: ipssh_v1_setup_stdio_channel() failed");
return IPCOM_ERR_FAILED;
}
ssh_conn->stdio_channel->data.shell.shell_fd =
ipssh_sock_shell_start(ssh_conn, ssh_conn->user, ssh_conn->sh_ctx);
if(ssh_conn->stdio_channel->data.shell.shell_fd == IP_INVALID_SOCKET)
{
IPCOM_LOG0(ERR, "ipssh_v1_msg_exec_shell :: shell_start_cb failed");
return IPCOM_ERR_FAILED;
}
ssh_conn->conn_state = IPSSH_CONN_STATE_SRV_TERM;
return IPCOM_SUCCESS;
}
/*
*===========================================================================
* ipssh_v1_msg_stdin_data
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL Ip_err
ipssh_v1_msg_stdin_data(Ipssh_conn* ssh_conn, Ipcom_buffer* pkt)
{
Ip_u8* data;
Ip_u32 in_len;
Ip_err rc = IPCOM_SUCCESS;
if( !(data=ipssh_buffer_get_sshbuf(pkt, &in_len)) )
{
IPCOM_LOG0(ERR, "ipssh_v1_msg_stdin_data :: failed to unpack message");
return IPCOM_ERR_FAILED;
}
ipssh_handle_term_modes(data, in_len, &(ssh_conn->stdio_channel->data.shell.term_modes));
if(ipssh_sock_shell_stdin(ssh_conn->stdio_channel->data.shell.shell_fd, (const char*)data, in_len) != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipssh_v1_msg_stdin_data :: shell_stdin_cb failed");
rc = IPCOM_ERR_FAILED;
goto cleanup;
}
#ifdef IPSSH_ECHO_STDIN
{
Ipcom_buffer* echo_pkt;
Ip_u8 last_chr = 0;
Ip_u32 pos = 0;
int len_pos;
Ip_u32 tmp_len;
next_line:
/* Required packet len = length of data to echo + length field + max pad len + packet type + crc + margin */
echo_pkt = ipssh_buffer_new_v1_pkt(in_len+4+8+1+4+8, IPSSH_SMSG_V1_STDOUT_DATA);
if(!echo_pkt)
{
IPCOM_LOG0(ERR, "ipssh_v1_msg_stdin_data :: out of memory");
return IPCOM_ERR_FAILED;
}
len_pos = ipcom_buffer_len(echo_pkt);
(void)ipcom_buffer_decr_cap(echo_pkt, 4);
tmp_len = ipcom_buffer_len(echo_pkt);
while(pos < in_len)
{
ipssh_store_echo_char(echo_pkt, &(ssh_conn->stdio_channel->data.shell.term_modes), data[pos], &last_chr);
/* Send a line at a time or all data, whatever occurs first */
pos++;
if(pos == in_len || data[pos] == '\r' || data[pos] == '\n'
|| ipcom_buffer_capacity(echo_pkt)<=(4+2) /* Leave room for crc */)
{
IPSSH_SET_32_PTR(ipcom_buffer_ptr2pos(echo_pkt, len_pos), ipcom_buffer_len(echo_pkt)-tmp_len);
if(ipssh_send_v1_pkt(ctx, echo_pkt) != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipssh_v1_msg_stdin_data :: failed to echo data");
return IPCOM_ERR_FAILED;
}
if(pos < in_len)
goto next_line;
}
}
}
#endif
cleanup:
if(data)
ipcom_free(data);
return rc;
}
/*
*===========================================================================
* ipssh_v1_msg_eof
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL Ip_err
ipssh_v1_msg_eof(Ipssh_conn* ssh_conn, Ipcom_buffer* pkt)
{
(void) ssh_conn;
(void) pkt;
if (ipcom_shutdown(ssh_conn->stdio_channel->data.shell.shell_fd, IP_SHUT_WR))
return IPCOM_ERR_FAILED;
return IPCOM_SUCCESS;
}
/*
*===========================================================================
* ipssh_v1_msg_window_size
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL Ip_err
ipssh_v1_msg_window_size(Ipssh_conn* ssh_conn, Ipcom_buffer* pkt)
{
Ip_u32 rows;
Ip_u32 columns;
Ip_u32 width;
Ip_u32 heigth;
(void) ssh_conn;
if(ipssh_buffer_get_uint(pkt, &rows) ||
ipssh_buffer_get_uint(pkt, &columns) ||
ipssh_buffer_get_uint(pkt, &width) ||
ipssh_buffer_get_uint(pkt, &heigth))
{
IPCOM_LOG0(ERR, "ipssh_v1_msg_window_size :: failed to unpack message");
return IPCOM_ERR_FAILED;
}
return IPCOM_SUCCESS;
}
/*
*===========================================================================
* ipssh_send_msg_v1_exit_status
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL Ip_err
ipssh_send_msg_v1_exit_status(Ipssh_conn* ssh_conn, Ip_u32 status)
{
Ipcom_buffer* pkt;
Ip_err rc;
pkt = ipssh_buffer_new_v1_pkt(64, IPSSH_SMSG_V1_EXITSTATUS);
if(!pkt)
{
IPCOM_LOG0(ERR, "ipssh_send_msg_v1_exit_status :: out of memory");
return IPCOM_ERR_FAILED;
}
(void)ipcom_buffer_put_int(pkt, ip_htonl(status));
rc = ipssh_send_v1_pkt(ssh_conn, pkt);
return rc;
}
/*
*===========================================================================
* ipssh_v1_msg_request_pty
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL Ip_err
ipssh_v1_msg_request_pty(Ipssh_conn* ssh_conn, Ipcom_buffer* pkt)
{
char* term;
Ip_u32 rows;
Ip_u32 columns;
Ip_u32 pixel_height;
Ip_u32 pixel_width;
Ip_err rc = IPCOM_SUCCESS;
if( !(term = ipssh_buffer_get_sshstr(pkt)) ||
ipssh_buffer_get_uint(pkt, &rows) ||
ipssh_buffer_get_uint(pkt, &columns) ||
ipssh_buffer_get_uint(pkt, &pixel_width) ||
ipssh_buffer_get_uint(pkt, &pixel_height) )
{
IPCOM_LOG0(ERR, "ipssh_v1_msg_request_pty :: failed to unpack message");
rc = IPCOM_ERR_FAILED;
goto cleanup;
}
if (ipssh_v1_setup_stdio_channel(ssh_conn) != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipssh_v1_msg_request_pty :: ipssh_v1_setup_stdio_channel() failed");
rc = IPCOM_ERR_FAILED;
goto cleanup;
}
if(ipssh_parse_terminal_modes_v1(pkt, &ssh_conn->stdio_channel->data.shell.term_modes) != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipssh_v1_msg_request_pty :: ipssh_parse_terminal_modes_v1 failed");
rc = IPCOM_ERR_FAILED;
goto cleanup;
}
if(ipssh_send_msg_v1_no_body(ssh_conn, IPSSH_SMSG_V1_SUCCESS) != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipssh_v1_msg_request_pty :: failed to unpack message");
rc = IPCOM_ERR_FAILED;
goto cleanup;
}
cleanup:
if(term)
ipcom_free(term);
return rc;
}
/*
*===========================================================================
* ipssh_v1_msg_port_open
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL Ip_err
ipssh_v1_msg_port_open(Ipssh_conn* ssh_conn, Ipcom_buffer* pkt)
{
Ip_err rc = IPCOM_SUCCESS;
Ip_u32 ch_id;
char* host_str = IP_NULL;
Ip_u32 port;
Ipssh_channel* channel;
Ip_fd sock;
/* Unpack message */
if( ipssh_buffer_get_uint(pkt, &ch_id) ||
!(host_str = ipssh_buffer_get_sshstr(pkt)) ||
ipssh_buffer_get_uint(pkt, &port) )
{
IPCOM_LOG0(ERR, "ipssh_v1_msg_port_open :: failed to unpack message");
rc = IPCOM_ERR_FAILED;
goto cleanup;
}
if(!ssh_conn->config.port_fwd)
{
IPCOM_LOG0(INFO, "ipssh_v1_msg_port_open :: port forwarding not turned on");
if(ipssh_send_msg_v1_channel_open_failure(ssh_conn, ch_id))
rc = IPCOM_ERR_FAILED;
goto cleanup;
}
if(ipssh_open_tcp_conn(host_str, port, &sock) != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipssh_v1_msg_port_open :: ipssh_open_tcp_conn() failed");
if(ipssh_send_msg_v1_channel_open_failure(ssh_conn, ch_id))
rc = IPCOM_ERR_FAILED;
goto cleanup;
}
channel = ipssh_channel_new(ssh_conn, ch_id, ipssh_channel2sock_handler);
if(!channel)
{
IPCOM_LOG0(ERR, "ipssh_v1_msg_port_open :: ipssh_channel_new2");
ipcom_socketclose(sock);
rc = IPCOM_ERR_FAILED;
goto cleanup;
}
channel->data.port_fwd.sock = sock;
channel->type = IPSSH_CH_TYPE_PORT_FWD;
if(ssh_conn->port_fwd_cb)
{
if(ssh_conn->port_fwd_cb(ssh_conn, channel->data.port_fwd.sock, IPSSH_PORT_FWD_EVENT_OPEN) != IPCOM_SUCCESS)
{
rc = IPCOM_ERR_FAILED;
goto cleanup;
}
}
if(ipssh_send_msg_v1_channel_open_confirmation(ssh_conn, channel) != IPCOM_SUCCESS)
rc = IPCOM_ERR_FAILED;
cleanup:
if(host_str)
ipcom_free(host_str);
return rc;
}
/*
*===========================================================================
* ipssh_v1_msg_port_forward_request
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL Ip_err
ipssh_v1_msg_port_forward_request(Ipssh_conn* ssh_conn, Ipcom_buffer* pkt)
{
Ip_u32 srv_port;
Ip_u32 conn_port;
char* host = IP_NULL;
Ip_err rc = IPCOM_SUCCESS;
Ip_fd sock;
/* Unpack message */
if(ipssh_buffer_get_uint(pkt, &srv_port) ||
!(host=ipssh_buffer_get_sshstr(pkt)) ||
ipssh_buffer_get_uint(pkt, &conn_port))
{
IPCOM_LOG0(ERR, "ipssh_v1_msg_port_forward_request :: failed to unpack message");
rc = IPCOM_ERR_FAILED;
goto cleanup;
}
if(!ssh_conn->config.port_fwd)
{
IPCOM_LOG0(ERR, "ipssh_v1_msg_port_forward_request :: port forwarding not turned on");
if(ipssh_send_msg_v1_no_body(ssh_conn, IPSSH_SMSG_V1_FAILURE))
rc = IPCOM_ERR_FAILED;
goto cleanup;
}
if(ipssh_setup_listen_sock("0.0.0.0", srv_port, &sock) != IPCOM_SUCCESS)
{
if(ipssh_send_msg_v1_no_body(ssh_conn, IPSSH_SMSG_V1_FAILURE))
rc = IPCOM_ERR_FAILED;
goto cleanup;
}
if(ipssh_store_port_fwd_addr(&(ssh_conn->port_fwd_addr_map), sock, host, conn_port) != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipssh_v1_msg_port_forward_request :: ipssh_store_port_fwd_addr() failed");
rc = IPCOM_ERR_FAILED;
goto cleanup;
}
if(ssh_conn->port_fwd_cb)
{
if(ssh_conn->port_fwd_cb(ssh_conn, sock, IPSSH_PORT_FWD_EVENT_LISTEN) != IPCOM_SUCCESS)
{
rc = IPCOM_ERR_FAILED;
goto cleanup;
}
}
if(ipssh_send_msg_v1_no_body(ssh_conn, IPSSH_SMSG_V1_SUCCESS))
rc = IPCOM_ERR_FAILED;
cleanup:
if(host)
ipcom_free(host);
return rc;
}
/*
*===========================================================================
* ipssh_v1_msg_channel_close
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL Ip_err
ipssh_v1_msg_channel_close(Ipssh_conn* ssh_conn, Ipcom_buffer* pkt)
{
Ipssh_channel* channel;
Ip_u32 my_ch_id;
Ipcom_buffer* send_pkt;
if(ipssh_buffer_get_uint(pkt, &my_ch_id))
{
IPCOM_LOG0(ERR, "ipssh_v1_msg_channel_close :: failed to unpack message");
return IPCOM_ERR_FAILED;
}
channel = ipssh_channel_id2ch(&ssh_conn->ch_map, my_ch_id);
if(!channel)
{
IPCOM_LOG1(DEBUG2, "ipssh_v1_msg_channel_close :: no channel data for id=%d", my_ch_id);
return IPCOM_SUCCESS;
}
send_pkt = ipssh_buffer_new_v1_pkt(64, IPSSH_MSG_V1_CHANNEL_CLOSE_CONFIRMATION);
if(!send_pkt)
{
IPCOM_LOG0(ERR, "ipssh_v1_msg_channel_close :: out of memory");
return IPCOM_ERR_FAILED;
}
(void)ipcom_buffer_put_int(send_pkt, ip_htonl(channel->peer_ch_id));
if(ipssh_send_v1_pkt(ssh_conn, send_pkt))
return IPCOM_ERR_FAILED;
ipssh_channel_close(channel);
return IPCOM_SUCCESS;
}
/*
*===========================================================================
* ipssh_v1_msg_channel_data
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL Ip_err
ipssh_v1_msg_channel_data(Ipssh_conn* ssh_conn, Ipcom_buffer* pkt)
{
Ipssh_channel* channel;
Ip_u32 my_ch_id;
if(ipssh_buffer_get_uint(pkt, &my_ch_id))
{
IPCOM_LOG0(ERR, "ipssh_v1_msg_channel_data :: failed to unpack message");
return IPCOM_ERR_FAILED;
}
channel = ipssh_channel_id2ch(&ssh_conn->ch_map, my_ch_id);
if(!channel)
{
IPCOM_LOG1(ERR, "ipssh_v1_msg_channel_data :: no channel data for id=%d", my_ch_id);
return IPCOM_ERR_FAILED;
}
if(channel->handler(channel, pkt) != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "ipssh_v1_msg_channel_data :: channel handler failed");
return IPCOM_ERR_FAILED;
}
return IPCOM_SUCCESS;
}
/*
*===========================================================================
* ipssh_v1_msg_channel_close_confirmation
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL Ip_err
ipssh_v1_msg_channel_close_confirmation(Ipssh_conn* ssh_conn, Ipcom_buffer* pkt)
{
Ip_u32 my_ch_id;
Ipssh_channel* channel;
if(ipssh_buffer_get_uint(pkt, &my_ch_id))
{
IPCOM_LOG0(ERR, "ipssh_v1_msg_channel_close_confirmation :: failed to unpack message");
return IPCOM_ERR_FAILED;
}
channel = ipssh_channel_id2ch(&ssh_conn->ch_map, my_ch_id);
if(!channel)
{
IPCOM_LOG0(ERR, "ipssh_v1_msg_channel_close_confirmation :: failed to unpack message");
return IPCOM_SUCCESS;
}
ipssh_channel_close(channel);
return IPCOM_SUCCESS;
}
/*
*===========================================================================
* ipssh_send_msg_v1_channel_data
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL Ip_err
ipssh_send_msg_v1_channel_data(Ipssh_conn* ssh_conn, Ip_u32 ch_id, Ip_u8* data, Ip_size_t len)
{
Ipcom_buffer* pkt;
/* pkt len = pkt len+max pad len+pkt type+ch id+data len+data+margin(10)*/
pkt = ipssh_buffer_new_v1_pkt(4+8+1+4+4+len +10, IPSSH_MSG_V1_CHANNEL_DATA);
if(!pkt)
return IPCOM_ERR_FAILED;
(void)ipcom_buffer_put_int(pkt, ip_htonl(ch_id));
(void)ipssh_buffer_put_sshbuf(pkt, data, len);
if(ipssh_send_v1_pkt(ssh_conn, pkt) != IPCOM_SUCCESS)
return IPCOM_ERR_FAILED;
return IPCOM_SUCCESS;
}
/*
*===========================================================================
* ipssh_send_msg_v1_channel_open_confirmation
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL Ip_err
ipssh_send_msg_v1_channel_open_confirmation(Ipssh_conn* ssh_conn, Ipssh_channel* channel)
{
Ipcom_buffer* pkt;
pkt = ipssh_buffer_new_v1_pkt(64, IPSSH_MSG_V1_CHANNEL_OPEN_CONFIRMATION);
if(!pkt)
return IPCOM_ERR_FAILED;
(void)ipcom_buffer_put_int(pkt, ip_htonl(channel->peer_ch_id));
(void)ipcom_buffer_put_int(pkt, ip_htonl(channel->my_ch_id));
if(ipssh_send_v1_pkt(ssh_conn, pkt) != IPCOM_SUCCESS)
return IPCOM_ERR_FAILED;
return IPCOM_SUCCESS;
}
/*
*===========================================================================
* ipssh_send_msg_v1_channel_open_failure
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL Ip_err
ipssh_send_msg_v1_channel_open_failure(Ipssh_conn* ssh_conn, Ip_u32 ch_id)
{
Ipcom_buffer* pkt;
pkt = ipssh_buffer_new_v1_pkt(64, IPSSH_MSG_V1_CHANNEL_OPEN_FAILURE);
if(!pkt)
return IPCOM_ERR_FAILED;
(void)ipcom_buffer_put_int(pkt, ip_htonl(ch_id));
if(ipssh_send_v1_pkt(ssh_conn, pkt) != IPCOM_SUCCESS)
return IPCOM_ERR_FAILED;
return IPCOM_SUCCESS;
}
/*
*===========================================================================
* ipssh_send_msg_v1_channel_close
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL Ip_err
ipssh_send_msg_v1_channel_close(Ipssh_conn* ssh_conn, Ipssh_channel* channel)
{
Ipcom_buffer* pkt;
pkt = ipssh_buffer_new_v1_pkt(32, IPSSH_MSG_V1_CHANNEL_CLOSE);
if(!pkt)
return IPCOM_ERR_FAILED;
(void)ipcom_buffer_put_int(pkt, ip_htonl(channel->peer_ch_id));
if(ipssh_send_v1_pkt(ssh_conn, pkt) != IPCOM_SUCCESS)
return IPCOM_ERR_FAILED;
return IPCOM_SUCCESS;
}
/*
*===========================================================================
* ipssh_v1_msg_channel_open_confirmation
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL Ip_err
ipssh_v1_msg_channel_open_confirmation(Ipssh_conn* ssh_conn, Ipcom_buffer* pkt)
{
Ipssh_channel* channel;
Ip_u32 my_ch_id;
Ip_u32 peer_ch_id;
/* Unpack message */
if(ipssh_buffer_get_uint(pkt, &my_ch_id) ||
ipssh_buffer_get_uint(pkt, &peer_ch_id))
{
IPCOM_LOG0(ERR, "ipssh_v1_msg_channel_open_confirmation :: failed to unpack message");
return IPCOM_ERR_FAILED;
}
channel = ipssh_channel_id2ch(&ssh_conn->ch_map, my_ch_id);
if(!channel)
{
IPCOM_LOG1(ERR, "ipssh_v1_msg_channel_open_confirmation :: no data for ch id=%d", my_ch_id);
return IPCOM_ERR_FAILED;
}
channel->peer_ch_id = peer_ch_id;
if(ssh_conn->port_fwd_cb)
if(ssh_conn->port_fwd_cb(ssh_conn, channel->data.port_fwd.sock, IPSSH_PORT_FWD_EVENT_OPEN))
return IPCOM_ERR_FAILED;
return IPCOM_SUCCESS;
}
/*
*===========================================================================
* ipssh_v1_msg_exit_confirmation
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL Ip_err
ipssh_v1_msg_exit_confirmation(Ipssh_conn* ssh_conn, Ipcom_buffer* pkt)
{
(void) ssh_conn;
(void) pkt;
return IPCOM_SUCCESS;
}
/*
*===========================================================================
* ipssh_port_fwd_handler_s2c_v1
*===========================================================================
* Description:
* Parameters:
* Returns:
*
*/
IP_GLOBAL Ip_err
ipssh_port_fwd_handler_s2c_v1(Ip_fd sock, Ipssh_conn_ctx* ctx, Ipssh_map_entry* map_entry)
{
Ipssh_channel* channel;
Ip_u8* data;
Ip_s32 rc = IPCOM_SUCCESS;
Ip_ssize_t read_bytes;
channel = ipssh_sock2channel(&ctx->ssh_conn->ch_map, sock);
if(!channel)
{
IPCOM_LOG1(ERR, "port_fwd_handler_s2c_v1 :: no channel data for socket: %d", sock);
return IPCOM_ERR_FAILED;
}
data = ipcom_malloc(IPSSH_PORT_FWD_CHUNK);
if(!data)
{
IPCOM_LOG0(ERR, "port_fwd_handler_s2c_v1 :: out of memory");
return IPCOM_ERR_FAILED;
}
read_bytes = ipcom_socketread(sock, data, IPSSH_PORT_FWD_CHUNK);
if(read_bytes <= 0) /* Port fwd connection closed */
{
if(read_bytes < 0)
{
IPCOM_LOG1(ERR, "port_fwd_handler_s2c_v1 :: connection lost, errno: %d", ipcom_errno);
}
ipcom_list_remove((Ipcom_list*)map_entry);
ipcom_free(map_entry);
IP_FD_CLR(sock, &(ctx->read_set));
if(!channel->close_sent)
{
if(ipssh_send_msg_v1_channel_close(ctx->ssh_conn, channel))
{
rc = IPCOM_ERR_FAILED;
goto cleanup;
}
}
if(channel->close_rec)
ipssh_channel_close(channel);
if(ctx->ssh_conn->ch_map.size == 0)
rc = IPCOM_ERR_FAILED; /* Last channel closed, close SSH connection */
}
else /* Forward data */
{
if(ipssh_send_msg_v1_channel_data(ctx->ssh_conn, channel->peer_ch_id, data, read_bytes) != IPCOM_SUCCESS)
{
IPCOM_LOG0(ERR, "port_fwd_handler_s2c_v1 :: ipssh_send_channel_data_msg() failed");
rc = IPCOM_ERR_FAILED;
goto cleanup;
}
}
cleanup:
if(data)
ipcom_free(data);
return rc;
}
#else
void ipssh_connection_v1_empty_file(void);
void ipssh_connection_v1_empty_file(void) { }
#endif /* IPSSH_USE_V1 */
/*
****************************************************************************
* END OF FILE
****************************************************************************
*/