/* ****************************************************************************** * 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 ****************************************************************************** */ /* **************************************************************************** * 1 DESCRIPTION **************************************************************************** */ /* **************************************************************************** * 2 CONFIGURATION **************************************************************************** */ #include #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 #include #include #include #include /* **************************************************************************** * 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 **************************************************************************** */