2414 lines
74 KiB
C
2414 lines
74 KiB
C
/*
|
|
******************************************************************************
|
|
* INTERPEAK SOURCE FILE
|
|
*
|
|
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipssh_sftp_clt.c,v $ $Revision: 1.36.10.3 $
|
|
* $Source: /home/interpeak/CVSRoot/ipssh/src/ipssh_sftp_clt.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"
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 3 INCLUDE FILES
|
|
****************************************************************************
|
|
*/
|
|
|
|
#ifdef IPSSH_USE_SFTP_CLT
|
|
|
|
#include "ipssh_h.h"
|
|
#include "ipssh.h"
|
|
#include "ipssh_transport.h"
|
|
#include "ipssh_buffer.h"
|
|
#include "ipssh_channel.h"
|
|
#include "ipssh_keyex_dh.h"
|
|
#include "ipssh_sftp.h"
|
|
#include "ipssh_sftp_clt.h"
|
|
|
|
#include <ipcom_clib.h>
|
|
#include <ipcom_type.h>
|
|
#include <ipcom_cstyle.h>
|
|
#include <ipcom_err.h>
|
|
#include <ipcom_sock.h>
|
|
#include <ipcom_sock2.h>
|
|
#include <ipcom_getopt.h>
|
|
|
|
#include "openssl/pem.h"
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 4 DEFINES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/* Version 3 is the most used version on the Internet. Most notably, openssh
|
|
* speaks sftp version 3. */
|
|
#define IPSSH_SFTP_VERSION 3
|
|
|
|
#define IPSSH_CLT2SRV 1
|
|
#define IPSSH_SRV2CLT 2
|
|
|
|
#define IPSSH_SFTP_CLT_HANDLE_MAGIC 0xDEAFBEEF
|
|
|
|
#ifndef IPSSH_SFTP_CLT_MAX_REQS
|
|
#define IPSSH_SFTP_CLT_MAX_REQS 10
|
|
#endif
|
|
/*
|
|
****************************************************************************
|
|
* 5 TYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
struct Ipssh_sftp_clt_dir_handle_st
|
|
{
|
|
Ip_u32 magic;
|
|
Ip_u8* ptr;
|
|
Ip_u32 len;
|
|
Ip_u32 count;
|
|
Ipcom_buffer* pkt;
|
|
Ipssh_dirent ret;
|
|
};
|
|
typedef struct Ipssh_sftp_clt_dir_handle_st Ipssh_sftp_clt_dir_handle;
|
|
|
|
struct Ipssh_sftp_clt_read_req_st
|
|
{
|
|
Ipcom_list list;
|
|
Ip_u32 req_id;
|
|
Ip_u32 len;
|
|
Ip_u64 offset;
|
|
|
|
};
|
|
typedef struct Ipssh_sftp_clt_read_req_st Ipssh_sftp_clt_read_req;
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 6 EXTERN PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 7 LOCAL PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
IP_GLOBAL Ip_err ipssh_send_fxp_init(Ipssh_channel* channel);
|
|
IP_GLOBAL Ip_err ipssh_send_fxp_realpath(Ipssh_channel* channel, const char* path);
|
|
IP_GLOBAL Ip_err ipssh_send_fxp_opendir(Ipssh_channel* channel, const char* path);
|
|
IP_GLOBAL Ip_err ipssh_send_fxp_readdir(Ipssh_channel* channel, Ip_u8* handle, Ip_u32 handle_len);
|
|
IP_GLOBAL Ip_err ipssh_send_fxp_close(Ipssh_channel* channel, Ip_u8* handle, Ip_u32 handle_len);
|
|
IP_GLOBAL Ip_err ipssh_send_fxp_open(Ipssh_channel* channel,
|
|
const char* path,
|
|
Ip_u32 flags,
|
|
Ip_u32 attr_flags,
|
|
struct Ip_stat* file_attr);
|
|
IP_GLOBAL Ip_err ipssh_send_fxp_read(Ipssh_channel* channel, const Ip_u8* handle,
|
|
Ip_u32 handle_len, Ipssh_sftp_clt_read_req* req);
|
|
|
|
IP_GLOBAL Ip_err ipssh_read_sftp_msg(Ipssh_channel* channel);
|
|
IP_GLOBAL Ip_err ipssh_msg_fxp_version(Ipssh_channel* channel, Ipcom_buffer* pkt);
|
|
IP_GLOBAL Ip_err ipssh_read_channel_data_msg(Ipssh_channel* channel);
|
|
|
|
IP_STATIC Ip_u32 ipssh_get_sftp_req_len(Ipssh_channel* channel, int direction, Ip_u32 old_req_len);
|
|
IP_STATIC Ip_err ipssh_make_abs_path(const char *cwd, const char *path, char *abs_path, Ip_size_t abs_path_len);
|
|
IP_STATIC Ipssh_sftp_clt_read_req* ipssh_sftp_clt_id2read_req(Ipcom_list* pending_reqs, Ip_u32 req_id);
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 8 DATA
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 9 STATIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
IP_STATIC Ip_err
|
|
ipssh_sftp_clt_dispatch_read_req(Ipssh_channel* channel,
|
|
Ipcom_list* pending_reqs,
|
|
Ipssh_sftp_clt_read_req* read_req,
|
|
const Ip_u8* handle,
|
|
Ip_u32 handle_len,
|
|
Ip_u32 req_id,
|
|
Ip_u64 offset,
|
|
Ip_u32 len)
|
|
{
|
|
ip_assert(!ipssh_sftp_clt_id2read_req(pending_reqs, req_id));
|
|
|
|
if (!read_req)
|
|
{
|
|
read_req = ipcom_calloc(1, sizeof(Ipssh_sftp_clt_read_req));
|
|
if (!read_req)
|
|
return IPCOM_ERR_NO_MEMORY;
|
|
ipcom_list_insert_last(pending_reqs, &read_req->list);
|
|
}
|
|
|
|
read_req->req_id = req_id;
|
|
IP_U64_COPY(read_req->offset, offset);
|
|
read_req->len = len;
|
|
|
|
return ipssh_send_fxp_read(channel, handle, handle_len, read_req);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* Ipssh_sftp_clt_id2read_req
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC Ipssh_sftp_clt_read_req*
|
|
ipssh_sftp_clt_id2read_req(Ipcom_list* pending_reqs, Ip_u32 req_id)
|
|
{
|
|
Ipssh_sftp_clt_read_req* req;
|
|
for(req = (Ipssh_sftp_clt_read_req*)ipcom_list_first(pending_reqs);
|
|
req;
|
|
req = (Ipssh_sftp_clt_read_req*)ipcom_list_next(&(req->list)))
|
|
{
|
|
if (req->req_id == req_id)
|
|
return req;
|
|
}
|
|
|
|
return IP_NULL;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_make_abs_path
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC Ip_err
|
|
ipssh_make_abs_path(const char *cwd, const char *path, char *abs_path, Ip_size_t abs_path_len)
|
|
{
|
|
ip_assert(path);
|
|
ip_assert(cwd);
|
|
ip_assert(abs_path);
|
|
|
|
if(path[0] != '/')
|
|
{
|
|
if(ipcom_strlen(cwd) + ipcom_strlen(path) >= abs_path_len)
|
|
return IPCOM_ERR_INVALID_ARG;
|
|
ipcom_strncpy(abs_path, cwd, IPSSH_SFTP_MAX_PATH);
|
|
if(cwd[ipcom_strlen(cwd)-1] != '/')
|
|
ipcom_strcat(abs_path, "/");
|
|
ipcom_strcat(abs_path, path);
|
|
}
|
|
else
|
|
{
|
|
if(ipcom_strlen(path) >= abs_path_len)
|
|
return IPCOM_ERR_INVALID_ARG;
|
|
|
|
ipcom_strcpy(abs_path, path);
|
|
}
|
|
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_get_sftp_req_len
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC Ip_u32
|
|
ipssh_get_sftp_req_len(Ipssh_channel* channel, int direction, Ip_u32 old_req_len)
|
|
{
|
|
Ip_u32 req_len = 16*1024-13; /* openssh uses a ch msg max size of 16k for sftp
|
|
* connections although a larger value typically
|
|
* is published in the
|
|
* SSH_MSG_CHANNEL_OPEN_CONFIRMATION.
|
|
* -13: We need to reserve space for sftp msg len
|
|
* and msg type, channel id and channel msg length */
|
|
|
|
switch(direction)
|
|
{
|
|
case IPSSH_CLT2SRV:
|
|
req_len = (Ip_u32)IP_MIN((Ip_s32)req_len, channel->peer_win);
|
|
req_len = IP_MIN(req_len, channel->peer_max_pkt_size);
|
|
break;
|
|
case IPSSH_SRV2CLT:
|
|
req_len = (Ip_u32)IP_MIN((Ip_s32)req_len, channel->my_win);
|
|
req_len = IP_MIN(req_len, channel->my_max_pkt_size);
|
|
break;
|
|
default:
|
|
IP_PANIC();
|
|
}
|
|
|
|
if (old_req_len == 0)
|
|
return req_len;
|
|
|
|
return IP_MIN(old_req_len, req_len);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_sftp_clt_wait_for_channel_win_adjust_msg
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC Ip_err
|
|
ipssh_sftp_clt_wait_for_channel_win_adjust_msg(Ipssh_channel* channel)
|
|
{
|
|
Ipssh_conn* ssh_conn;
|
|
|
|
ssh_conn = channel->ssh_conn;
|
|
|
|
if(ipssh_read_v2_pkt(ssh_conn) != IPCOM_SUCCESS)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_sftp_clt_wait_for_channel_win_adjust_msg :: ipssh_read_v2_pkt() failed");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
if(IPSSH_GET_PKT_TYPE(ipcom_buffer_start_ptr(ssh_conn->recv_plain_buf)) == IPSSH_MSG_CHANNEL_WINDOW_ADJUST)
|
|
{
|
|
if(ipssh_pkt_dispatch(ssh_conn) != IPCOM_SUCCESS)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_sftp_clt_wait_for_channel_win_adjust_msg :: ipssh_pkt_dispatch() failed");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
IPCOM_LOG1(ERR, "ipssh_sftp_clt_wait_for_channel_win_adjust_msg :: unexpected msg received: %d",
|
|
IPSSH_GET_PKT_TYPE(ipcom_buffer_start_ptr(ssh_conn->recv_plain_buf)));
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_sftp_clt_check_ch_win
|
|
*===========================================================================
|
|
* Description: Checks that we have a big enough channel window to send
|
|
* an sftp message. If the window size is too small, we wait for
|
|
* an IPSSH_MSG_CHANNEL_WINDOW_ADJUST msg.
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC void
|
|
ipssh_sftp_clt_check_ch_win(Ipssh_channel* channel, int min_win_size)
|
|
{
|
|
while (1)
|
|
{
|
|
if (channel->peer_win < min_win_size)
|
|
{
|
|
if (ipssh_sftp_clt_wait_for_channel_win_adjust_msg(channel) != IPCOM_SUCCESS)
|
|
return;
|
|
}
|
|
else
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 10 GLOBAL FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
|
|
IP_GLOBAL Ip_err
|
|
ipssh_read_channel_data_msg(Ipssh_channel* channel)
|
|
{
|
|
Ipssh_conn* ssh_conn;
|
|
Ip_u8 msg_type;
|
|
Ip_err rc;
|
|
|
|
ssh_conn = channel->ssh_conn;
|
|
|
|
while (1)
|
|
{
|
|
if(ipssh_read_v2_pkt(ssh_conn) != IPCOM_SUCCESS)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_read_channel_data_msg :: ipssh_read_v2_pkt() failed");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
msg_type = IPSSH_GET_PKT_TYPE(ipcom_buffer_start_ptr(ssh_conn->recv_plain_buf));
|
|
if(msg_type == IPSSH_MSG_CHANNEL_DATA)
|
|
return IPCOM_SUCCESS;
|
|
|
|
if(ipssh_pkt_dispatch(ssh_conn) != IPCOM_SUCCESS)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_read_channel_data_msg :: ipssh_pkt_dispatch() failed");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
if (msg_type == IPSSH_MSG_KEXINIT)
|
|
{
|
|
IPCOM_LOG0(INFO, "ipssh_read_channel_data_msg :: rekeying requested by peer");
|
|
switch(ssh_conn->conn_prop_pending.kex_alg[0])
|
|
{
|
|
case IPSSH_KEYEX_DH_GR1_SHA1_ID:
|
|
rc = ipssh_do_keyex_dh_clt(ssh_conn);
|
|
if (rc != IPCOM_SUCCESS)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_read_channel_data_msg :: ipssh_do_keyex_dh_clt() failed");
|
|
return rc;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
IP_PANIC();
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_read_sftp_msg
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipssh_read_sftp_msg(Ipssh_channel* channel)
|
|
{
|
|
Ipssh_conn* ssh_conn;
|
|
Ip_u32 ch_id = 0;
|
|
Ip_u32 ch_data_len = 0;
|
|
Ip_u32 sftp_msg_len;
|
|
|
|
ssh_conn = channel->ssh_conn;
|
|
|
|
while(1)
|
|
{
|
|
if (!channel->data.sftp.msg) /* No sftp msg data read */
|
|
{
|
|
if(ipssh_read_channel_data_msg(channel) != IPCOM_SUCCESS)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_read_sftp_msg :: ipssh_read_channel_data_msg() failed");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
if(ipcom_buffer_consume(ssh_conn->recv_plain_buf, 6)
|
|
|| ipssh_buffer_get_uint(ssh_conn->recv_plain_buf, &ch_id)
|
|
|| ipssh_buffer_get_uint(ssh_conn->recv_plain_buf, &ch_data_len))
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_read_sftp_msg :: failed to unpack channel data msg");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
if(ipssh_send_channel_win_adjust_msg(channel, ch_data_len))
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_read_sftp_msg :: ipssh_send_channel_win_adjust failed");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
sftp_msg_len = IP_GET_NTOHL(ipcom_buffer_start_ptr(ssh_conn->recv_plain_buf))+4;
|
|
|
|
/* Exactly one complete sftp msg received */
|
|
if ((sftp_msg_len) == ipcom_buffer_len(ssh_conn->recv_plain_buf))
|
|
{
|
|
if(ipcom_buffer_consume(ssh_conn->recv_plain_buf, 4))
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_read_sftp_msg :: failed to unpack sftp msg len");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
/* More than one complete sftp msg received */
|
|
if (ipcom_buffer_len(ssh_conn->recv_plain_buf) > sftp_msg_len)
|
|
{
|
|
Ip_u32 next_sftp_frag_len;
|
|
|
|
next_sftp_frag_len = ipcom_buffer_len(ssh_conn->recv_plain_buf) - (sftp_msg_len);
|
|
channel->data.sftp.msg = ipcom_buffer_new(next_sftp_frag_len);
|
|
if (!channel->data.sftp.msg)
|
|
return IPCOM_ERR_NO_MEMORY;
|
|
(void)ipcom_buffer_put(channel->data.sftp.msg,
|
|
(Ip_u8*)ipcom_buffer_ptr2pos(ssh_conn->recv_plain_buf, sftp_msg_len),
|
|
next_sftp_frag_len);
|
|
(void)ipcom_buffer_consume_end(ssh_conn->recv_plain_buf, next_sftp_frag_len);
|
|
(void)ipcom_buffer_consume(ssh_conn->recv_plain_buf, 4); /* Skip sftp msg len */
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
/* The sftp message is fragmented into several ch data msgs */
|
|
if(sftp_msg_len > ipcom_buffer_len(ssh_conn->recv_plain_buf))
|
|
{
|
|
channel->data.sftp.msg = ipcom_buffer_new(sftp_msg_len);
|
|
if (!channel->data.sftp.msg)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_read_sftp_msg :: out of memory");
|
|
return IPCOM_ERR_NO_MEMORY;
|
|
}
|
|
(void)ipcom_buffer_put(channel->data.sftp.msg,
|
|
ipcom_buffer_start_ptr(ssh_conn->recv_plain_buf),
|
|
ipcom_buffer_len(ssh_conn->recv_plain_buf));
|
|
}
|
|
}
|
|
|
|
if(channel->data.sftp.msg) /* sftp msg data already read */
|
|
{
|
|
Ipcom_buffer* tmp_buf = IP_NULL;
|
|
|
|
sftp_msg_len = IP_GET_NTOHL(ipcom_buffer_start_ptr(channel->data.sftp.msg))+4;
|
|
|
|
/* We now have a complete sftp message in channel->data.sftp.msg */
|
|
if (ipcom_buffer_len(channel->data.sftp.msg) == sftp_msg_len)
|
|
{
|
|
ipcom_buffer_free(ssh_conn->recv_plain_buf);
|
|
ssh_conn->recv_plain_buf = channel->data.sftp.msg;
|
|
channel->data.sftp.msg = IP_NULL;
|
|
if(ipssh_buffer_get_uint(ssh_conn->recv_plain_buf, &sftp_msg_len))
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_read_sftp_msg :: failed to unpack sftp msg len");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
/* More than one sftp msg in channel->data.sftp.msg */
|
|
if (ipcom_buffer_len(channel->data.sftp.msg) > sftp_msg_len)
|
|
{
|
|
Ip_u32 next_sftp_msg_frag;
|
|
|
|
next_sftp_msg_frag = ipcom_buffer_len(channel->data.sftp.msg) - (sftp_msg_len);
|
|
tmp_buf = ipcom_buffer_new(next_sftp_msg_frag);
|
|
if (!tmp_buf)
|
|
{
|
|
IPCOM_LOG1(ERR, "ipssh_read_sftp_msg :: failed to allocate %d bytes", next_sftp_msg_frag);
|
|
return IPCOM_ERR_NO_MEMORY;
|
|
}
|
|
(void)ipcom_buffer_put(tmp_buf,
|
|
(Ip_u8*)ipcom_buffer_ptr2pos(channel->data.sftp.msg, sftp_msg_len),
|
|
next_sftp_msg_frag);
|
|
ssh_conn->recv_plain_buf = channel->data.sftp.msg;
|
|
channel->data.sftp.msg = tmp_buf;
|
|
(void)ipcom_buffer_consume(ssh_conn->recv_plain_buf, 4);
|
|
(void)ipcom_buffer_consume_end(ssh_conn->recv_plain_buf, next_sftp_msg_frag);
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
/* If we get here we only have a fragment of the sftp msg. Read a channel data msg */
|
|
if(ipssh_read_channel_data_msg(channel) != IPCOM_SUCCESS)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_read_sftp_msg :: ipssh_read_channel_data_msg() failed");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
if(ipcom_buffer_consume(ssh_conn->recv_plain_buf, 6)
|
|
|| ipssh_buffer_get_uint(ssh_conn->recv_plain_buf, &ch_id)
|
|
|| ipssh_buffer_get_uint(ssh_conn->recv_plain_buf, &ch_data_len))
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_read_sftp_msg :: failed to unpack channel data msg");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
if(ipssh_send_channel_win_adjust_msg(channel, ch_data_len))
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_read_sftp_msg :: ipssh_send_channel_win_adjust failed");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
(void)ipcom_buffer_put(channel->data.sftp.msg, ipcom_buffer_start_ptr(ssh_conn->recv_plain_buf), ch_data_len);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_send_fxp_readdir
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipssh_send_fxp_readdir(Ipssh_channel* channel, Ip_u8* handle, Ip_u32 handle_len)
|
|
{
|
|
Ip_err rc = IPCOM_ERR_FAILED;
|
|
Ipcom_buffer* pkt;
|
|
|
|
pkt = ipssh_buffer_new_sftp_pkt(32+handle_len, IPSSH_FXP_READDIR);
|
|
if(!pkt)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_send_readdir :: out of memory");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
channel->data.sftp.req_id++;
|
|
(void)ipssh_buffer_put_int(pkt, channel->data.sftp.req_id);
|
|
(void)ipssh_buffer_put_sshbuf(pkt, handle, handle_len);
|
|
|
|
rc = ipssh_send_fxp_msg(channel, pkt);
|
|
|
|
ipcom_buffer_free(pkt);
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_send_fxp_close
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipssh_send_fxp_close(Ipssh_channel* channel, Ip_u8* handle, Ip_u32 handle_len)
|
|
{
|
|
Ip_err rc = IPCOM_ERR_FAILED;
|
|
Ipcom_buffer* pkt;
|
|
Ip_u8 pkt_type;
|
|
Ip_u32 req_id;
|
|
Ip_u32 status;
|
|
|
|
pkt = ipssh_buffer_new_sftp_pkt(32+handle_len, IPSSH_FXP_CLOSE);
|
|
if(!pkt)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_send_fxp_close :: out of memory");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
channel->data.sftp.req_id++;
|
|
|
|
(void)ipssh_buffer_put_int(pkt, channel->data.sftp.req_id);
|
|
(void)ipssh_buffer_put_sshbuf(pkt, handle, handle_len);
|
|
|
|
if(ipssh_send_fxp_msg(channel, pkt))
|
|
goto cleanup;
|
|
|
|
/* Read reply */
|
|
if(ipssh_read_sftp_msg(channel))
|
|
goto cleanup;
|
|
if(ipcom_buffer_get_char(channel->ssh_conn->recv_plain_buf, &pkt_type))
|
|
goto cleanup;
|
|
if(pkt_type == IPSSH_FXP_STATUS)
|
|
{
|
|
if(ipssh_buffer_get_uint(channel->ssh_conn->recv_plain_buf, &req_id)
|
|
|| ipssh_buffer_get_uint(channel->ssh_conn->recv_plain_buf, &status))
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_sftp_clt_close :: failed to unpack FXP_STATUS msg");
|
|
goto cleanup;
|
|
}
|
|
if(status == IPSSH_FX_OK)
|
|
rc = IPCOM_SUCCESS;
|
|
}
|
|
|
|
cleanup:
|
|
if(pkt)
|
|
ipcom_buffer_free(pkt);
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_send_fxp_opendir
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipssh_send_fxp_opendir(Ipssh_channel* channel, const char* path)
|
|
{
|
|
Ip_err rc = IPCOM_ERR_FAILED;
|
|
Ipcom_buffer* pkt;
|
|
|
|
pkt = ipssh_buffer_new_sftp_pkt(32+ipcom_strlen(path), IPSSH_FXP_OPENDIR);
|
|
if(!pkt)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_send_opendir :: out of memory");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
channel->data.sftp.req_id++;
|
|
(void)ipssh_buffer_put_int(pkt, channel->data.sftp.req_id);
|
|
(void)ipssh_buffer_put_sshstr(pkt, path);
|
|
|
|
rc = ipssh_send_fxp_msg(channel, pkt);
|
|
|
|
ipcom_buffer_free(pkt);
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_send_fxp_realpath
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipssh_send_fxp_realpath(Ipssh_channel* channel, const char* path)
|
|
{
|
|
Ip_err rc;
|
|
Ipcom_buffer* pkt;
|
|
|
|
IPCOM_LOG0(DEBUG, "ipssh_send_fxp_realpath ::");
|
|
|
|
pkt = ipssh_buffer_new_sftp_pkt(32+ipcom_strlen(path), IPSSH_FXP_REALPATH);
|
|
if(!pkt)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_send_fxp_realpath :: out of memory");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
channel->data.sftp.req_id++;
|
|
(void)ipssh_buffer_put_int(pkt, channel->data.sftp.req_id);
|
|
(void)ipssh_buffer_put_sshstr(pkt, path);
|
|
|
|
rc = ipssh_send_fxp_msg(channel, pkt);
|
|
|
|
ipcom_buffer_free(pkt);
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_send_fxp_init
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipssh_send_fxp_init(Ipssh_channel* channel)
|
|
{
|
|
Ip_err rc = IPCOM_ERR_FAILED;
|
|
Ipcom_buffer* pkt;
|
|
|
|
IPCOM_LOG0(DEBUG, "ipssh_send_fxp_init ::");
|
|
|
|
pkt = ipssh_buffer_new_sftp_pkt(32, IPSSH_FXP_INIT);
|
|
if(!pkt)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_send_fxp_init :: out of memory");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
(void)ipssh_buffer_put_int(pkt, IPSSH_SFTP_VERSION);
|
|
if(ipssh_send_fxp_msg(channel, pkt))
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_send_fxp_init :: ipssh_send_pkt failed");
|
|
goto cleanup;
|
|
}
|
|
|
|
channel->state = IPSSH_CH_STATE_CLT_FXP_INIT_SENT;
|
|
rc = IPCOM_SUCCESS;
|
|
|
|
cleanup:
|
|
if(pkt)
|
|
ipcom_buffer_free(pkt);
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_send_fxp_open
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipssh_send_fxp_open(Ipssh_channel* channel, const char* path, Ip_u32 flags, Ip_u32 attr_flags, struct Ip_stat* file_attr)
|
|
{
|
|
Ipcom_buffer* pkt;
|
|
Ip_err rc = IPCOM_ERR_FAILED;
|
|
|
|
pkt = ipssh_buffer_new_sftp_pkt(32 + ipcom_strlen(path), IPSSH_FXP_OPEN);
|
|
if(!pkt)
|
|
return IPCOM_ERR_NO_MEMORY;
|
|
|
|
channel->data.sftp.req_id++;
|
|
if(ipssh_buffer_put_uint(pkt, channel->data.sftp.req_id)
|
|
|| ipssh_buffer_put_sshstr(pkt, path)
|
|
|| ipssh_buffer_put_uint(pkt, flags))
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_send_fxp_open :: failed to pack msg");
|
|
goto cleanup;
|
|
}
|
|
|
|
if(ipssh_pack_attr(pkt, file_attr, attr_flags) != IPCOM_SUCCESS)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_send_fxp_open :: ipssh_pack_attr failed");
|
|
goto cleanup;
|
|
}
|
|
|
|
rc = ipssh_send_fxp_msg(channel, pkt);
|
|
|
|
cleanup:
|
|
ipcom_buffer_free(pkt);
|
|
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_send_fxp_read
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipssh_send_fxp_read(Ipssh_channel* channel, const Ip_u8* handle, Ip_u32 handle_len, Ipssh_sftp_clt_read_req* req)
|
|
{
|
|
Ipcom_buffer* pkt;
|
|
Ip_err rc = IPCOM_ERR_FAILED;
|
|
|
|
pkt = ipssh_buffer_new_sftp_pkt(32 + handle_len, IPSSH_FXP_READ);
|
|
if(!pkt)
|
|
return IPCOM_ERR_NO_MEMORY;
|
|
|
|
if(ipssh_buffer_put_uint(pkt, req->req_id)
|
|
|| ipssh_buffer_put_sshbuf(pkt, handle, handle_len)
|
|
|| ipssh_buffer_put_u64(pkt, req->offset)
|
|
|| ipssh_buffer_put_uint(pkt, req->len))
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_send_fxp_read :: failed to pack msg");
|
|
ipcom_buffer_free(pkt);
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
rc = ipssh_send_fxp_msg(channel, pkt);
|
|
|
|
ipcom_buffer_free(pkt);
|
|
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_msg_fxp_version
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipssh_msg_fxp_version(Ipssh_channel* channel, Ipcom_buffer* pkt)
|
|
{
|
|
Ip_u32 version;
|
|
Ip_u8* len_ptr;
|
|
int ext_len;
|
|
|
|
IPCOM_LOG0(DEBUG, "ipssh_msg_fxp_version ::");
|
|
|
|
/* Get length field so we can figure out if the packet contains any
|
|
* extension data */
|
|
len_ptr = ipcom_buffer_start_ptr(pkt);
|
|
len_ptr -= 5; /* Back up to the length field */
|
|
ext_len = ip_ntohl(IP_GET_32ON8(len_ptr))-1-4;
|
|
|
|
/* Unpack msg */
|
|
if(ipssh_buffer_get_uint(pkt, &version))
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_msg_fxp_version :: failed to unpack msg");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
if(version != IPSSH_SFTP_VERSION)
|
|
{
|
|
IPCOM_LOG1(ERR, "ipssh_msg_fxp_version :: unexpected version %d", version );
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
channel->state = IPSSH_CH_STATE_CLT_SFTP;
|
|
|
|
/* Read/remove extension data */
|
|
while (ext_len>0)
|
|
{
|
|
char* ext_name;
|
|
char* ext_data;
|
|
Ip_bool ok = IP_FALSE;
|
|
|
|
ext_name = ipssh_buffer_get_sshstr(pkt);
|
|
ext_data = ipssh_buffer_get_sshstr(pkt);
|
|
if (ext_name && ext_data)
|
|
{
|
|
ext_len = pkt->end - pkt->offset;
|
|
ok = IP_TRUE;
|
|
}
|
|
if (ext_name)
|
|
ipcom_free(ext_name);
|
|
if (ext_data)
|
|
ipcom_free(ext_data);
|
|
if (!ok)
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_sftp_clt_pkt_dispatch
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipssh_sftp_clt_pkt_dispatch(Ipssh_channel* channel, Ipcom_buffer* pkt)
|
|
{
|
|
Ip_u8 pkt_type;
|
|
Ip_err rc;
|
|
Ip_u32 req_id;
|
|
|
|
if(ipcom_buffer_get_char(pkt, &pkt_type) != IPCOM_SUCCESS)
|
|
return IPCOM_ERR_FAILED;
|
|
|
|
IPCOM_LOG2(DEBUG2, "ipssh_sftp_clt_pkt_dispatch :: pkt type: %d, data_len:%d",
|
|
pkt_type, ipcom_buffer_len(pkt));
|
|
|
|
switch(pkt_type)
|
|
{
|
|
case IPSSH_FXP_VERSION:
|
|
rc = ipssh_msg_fxp_version(channel, pkt);
|
|
break;
|
|
|
|
/* Message an sftp client should never receive */
|
|
case IPSSH_FXP_CLOSE:
|
|
case IPSSH_FXP_OPENDIR:
|
|
case IPSSH_FXP_READDIR:
|
|
case IPSSH_FXP_OPEN:
|
|
default:
|
|
if(ipssh_buffer_get_uint(pkt, &req_id) == IPCOM_SUCCESS)
|
|
{
|
|
(void)ipssh_send_fxp_status(channel, req_id, IPSSH_FX_BAD_MESSAGE);
|
|
IPCOM_LOG3(ERR, "ipssh_sftp_clt_pkt_dispatch :: unknown pkt type: %d, ch_id: %d, req_id: %d",
|
|
pkt_type, channel->my_ch_id, req_id);
|
|
}
|
|
IP_PANIC2();
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 11 PUBLIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_sftp_clt_open
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_PUBLIC Ip_err
|
|
ipssh_sftp_clt_open(Ipssh_conn* ssh_conn, const char* hostname, Ip_u16 port)
|
|
{
|
|
Ip_err rc;
|
|
Ipcom_buffer* pkt;
|
|
Ipssh_channel* channel;
|
|
|
|
if(!ssh_conn || !hostname || !ssh_conn->data.clt.userid[0]
|
|
|| (!ssh_conn->data.clt.pw[0] && !ssh_conn->data.clt.key && !ssh_conn->data.clt.host_key)) /* One of pw, pubkey or hostbased auth data must be supplied */
|
|
{
|
|
IP_PANIC2();
|
|
return IPCOM_ERR_INVALID_ARG;
|
|
}
|
|
ssh_conn->mode = IPSSH_MODE_CLT;
|
|
|
|
rc = ipssh_setup_clt_transport(ssh_conn, hostname, port);
|
|
if(rc != IPCOM_SUCCESS)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_sftp_clt_open, ipssh_setup_clt_transport");
|
|
return rc;
|
|
}
|
|
|
|
ssh_conn->data.clt.channel = ipssh_channel_new(ssh_conn, 0xffffffff, ipssh_channel_data_sftp_handler);
|
|
if(!ssh_conn->data.clt.channel)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_sftp_clt_open :: ipssh_channel_new failed");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
channel = ssh_conn->data.clt.channel;
|
|
ipssh_channel_sftp_init(channel, IPSSH_CH_TYPE_SFTP_CLT);
|
|
channel->ssh_conn = ssh_conn;
|
|
|
|
pkt = ipssh_get_channel_open_pkt(channel, IPSSH_SESSION, 128);
|
|
if(!pkt)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_sftp_clt_open :: ipssh_get_channel_open_pkt failed");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
rc = ipssh_send_pkt(ssh_conn, pkt, IP_TRUE);
|
|
if(rc != IPCOM_SUCCESS)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_sftp_clt_open :: ipssh_send_pkt failed");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
channel->state = IPSSH_CH_STATE_CH_OPEN_SENT;
|
|
while(channel->state != IPSSH_CH_STATE_CLT_SFTP)
|
|
{
|
|
switch(channel->state)
|
|
{
|
|
case IPSSH_CH_STATE_CH_OPEN_SENT:
|
|
case IPSSH_CH_STATE_CH_REQUEST_SENT:
|
|
case IPSSH_CH_STATE_CLT_FXP_INIT_SENT:
|
|
if(ipssh_read_and_dispatch_v2_pkt(ssh_conn, 0) != IPCOM_SUCCESS)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_sftp_clt_open :: ipssh_read_and_dispatch_v2_pkt failed");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
break;
|
|
case IPSSH_CH_STATE_OPENED:
|
|
if(ipssh_send_channel_request_subsystem(channel, 1, IPSSH_SFTP_STR) != IPCOM_SUCCESS)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_sftp_clt_open :: ipssh_send_channel_request_subsystem failed");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
break;
|
|
|
|
case IPSSH_CH_STATE_CH_REQUEST_OK:
|
|
if(ipssh_send_fxp_init(channel) != IPCOM_SUCCESS)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_sftp_clt_open :: ipssh_send_ftp_init failed");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
IP_PANIC();
|
|
}
|
|
}
|
|
|
|
channel->data.sftp.cwd = ipcom_malloc(IPSSH_SFTP_MAX_PATH);
|
|
if(!channel->data.sftp.cwd)
|
|
return IPCOM_ERR_FAILED;
|
|
if(ipssh_sftp_clt_get_realpath(ssh_conn, ".", channel->data.sftp.cwd, IPSSH_SFTP_MAX_PATH) != IPCOM_SUCCESS)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_sftp_clt_open :: ipssh_sftp_clt_get_realpath failed");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_sftp_clt_get
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_PUBLIC Ip_err
|
|
ipssh_sftp_clt_get(Ipssh_conn* ssh_conn, const char* remote_path, const char* local_path)
|
|
{
|
|
Ip_err rc = IPCOM_ERR_FAILED;
|
|
Ip_u8 pkt_type;
|
|
char abs_remote_path[IPSSH_SFTP_MAX_PATH];
|
|
Ipssh_channel* channel;
|
|
Ip_u32 req_id;
|
|
Ip_u32 error;
|
|
Ip_u8* handle = IP_NULL;
|
|
Ip_u32 handle_len;
|
|
int fd;
|
|
Ipssh_sftp_func_cb* func;
|
|
Ip_u64 offset;
|
|
Ipcom_list pending_reqs;
|
|
Ipssh_sftp_clt_read_req* read_req;
|
|
Ip_u32 max_reqs;
|
|
Ip_u32 read_len = 0;
|
|
|
|
ipcom_list_init(&pending_reqs);
|
|
|
|
max_reqs = ipcom_sysvar_get_as_int("ipssh.sftp.clt_max_reqs", 4);
|
|
if (max_reqs < 1)
|
|
max_reqs = 1;
|
|
if (max_reqs > IPSSH_SFTP_CLT_MAX_REQS)
|
|
max_reqs = IPSSH_SFTP_CLT_MAX_REQS;
|
|
|
|
if(ssh_conn->conn_state != IPSSH_CONN_STATE_CLT_CONNECTED || !ssh_conn->data.clt.channel
|
|
|| !local_path || !remote_path || ipcom_strlen(local_path) > IPSSH_SFTP_MAX_PATH
|
|
|| ipcom_strlen(remote_path) > IPSSH_SFTP_MAX_PATH)
|
|
{
|
|
IP_PANIC2();
|
|
return IPCOM_ERR_INVALID_ARG;
|
|
}
|
|
|
|
channel = ssh_conn->data.clt.channel;
|
|
|
|
func = ipssh_get_sftp_func_cb(local_path);
|
|
if(!func)
|
|
return IPCOM_ERR_FAILED;
|
|
|
|
if(ipssh_make_abs_path(channel->data.sftp.cwd, remote_path, abs_remote_path, IPSSH_SFTP_MAX_PATH) != IPCOM_SUCCESS)
|
|
return IPCOM_ERR_INVALID_ARG;
|
|
|
|
/* Open local file */
|
|
fd = func->open_cb(local_path, IP_O_WRONLY|IP_O_CREAT|IP_O_TRUNC, 0666);
|
|
if(fd == -1)
|
|
{
|
|
IPCOM_LOG1(ERR, "ipssh_sftp_clt_get :: failed to open local file: %s", local_path);
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
if(ipssh_send_fxp_open(channel, abs_remote_path, IPSSH_FXF_READ, 0, IP_NULL))
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_sftp_clt_get :: ipssh_send_fxp_open() failed");
|
|
goto cleanup;
|
|
}
|
|
|
|
if(ipssh_read_sftp_msg(channel))
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_sftp_clt_get :: ipssh_read_sftp_msg() failed");
|
|
goto cleanup;
|
|
}
|
|
|
|
if(ipcom_buffer_get_char(ssh_conn->recv_plain_buf, &pkt_type))
|
|
goto cleanup;
|
|
switch(pkt_type)
|
|
{
|
|
case IPSSH_FXP_HANDLE:
|
|
if(ipssh_buffer_get_uint(ssh_conn->recv_plain_buf, &req_id)
|
|
|| (handle = ipssh_buffer_get_sshbuf(ssh_conn->recv_plain_buf, &handle_len)) == IP_NULL)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_sftp_clt_get :: failed to unpack FXP_HANDLE msg");
|
|
goto cleanup;
|
|
}
|
|
break;
|
|
|
|
case IPSSH_FXP_STATUS:
|
|
if(ipssh_buffer_get_uint(ssh_conn->recv_plain_buf, &req_id)
|
|
|| ipssh_buffer_get_uint(ssh_conn->recv_plain_buf, &error))
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_sftp_clt_get :: failed to unpack FXP_STATUS msg");
|
|
goto cleanup;
|
|
}
|
|
switch(error)
|
|
{
|
|
case IPSSH_FX_NO_SUCH_FILE:
|
|
rc = IPCOM_ERR_NOT_FOUND;
|
|
goto cleanup;
|
|
case IPSSH_FX_PERMISSION_DENIED:
|
|
rc = IPCOM_ERR_PERMISSION_DENIED;
|
|
goto cleanup;
|
|
default:
|
|
goto cleanup;
|
|
}
|
|
|
|
default:
|
|
IPCOM_LOG1(ERR, "ipssh_sftp_clt_get :: unexpected sftp msg received: %d", pkt_type);
|
|
goto cleanup;
|
|
}
|
|
|
|
IP_U64_CLEAR(offset);
|
|
/* File opened, start reading */
|
|
do
|
|
{
|
|
Ip_u32 data_len;
|
|
|
|
if (ipcom_list_length(&pending_reqs) == 0)
|
|
{
|
|
read_len = ipssh_get_sftp_req_len(channel, IPSSH_SRV2CLT, 0);
|
|
|
|
if (ipssh_sftp_clt_dispatch_read_req(channel,
|
|
&pending_reqs,
|
|
IP_NULL,
|
|
handle,
|
|
handle_len,
|
|
++channel->data.sftp.req_id,
|
|
0,
|
|
read_len) != IPCOM_SUCCESS)
|
|
{
|
|
IPCOM_LOG2(ERR, "ipssh_sftp_clt_get :: failed to dispatch initial read request: local path: %s, remote path: %s",
|
|
local_path, remote_path);
|
|
goto cleanup;
|
|
}
|
|
IP_U64_ADD32(offset, read_len);
|
|
}
|
|
|
|
if(ipssh_read_sftp_msg(channel))
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_sftp_clt_get :: ipssh_read_sftp_msg() failed");
|
|
goto cleanup;
|
|
}
|
|
|
|
if(ipcom_buffer_get_char(ssh_conn->recv_plain_buf, &pkt_type))
|
|
goto cleanup;
|
|
switch(pkt_type)
|
|
{
|
|
case IPSSH_FXP_DATA:
|
|
case IPSSH_FXP_STATUS:
|
|
if (ipssh_buffer_get_uint(ssh_conn->recv_plain_buf, &req_id))
|
|
{
|
|
IPCOM_LOG1(ERR, "ipssh_sftp_clt_get :: failed to unpack req_id in %s msg",
|
|
pkt_type == IPSSH_FXP_DATA ? "FXP_DATA": "FXP_STATUS");
|
|
goto cleanup;
|
|
}
|
|
read_req = ipssh_sftp_clt_id2read_req(&pending_reqs, req_id);
|
|
if (!read_req)
|
|
{
|
|
IPCOM_LOG2(ERR, "ipssh_sftp_clt_get :: unexpected req_id (%d) received in %s msg",
|
|
req_id, pkt_type == IPSSH_FXP_DATA ? "FXP_DATA": "FXP_STATUS");
|
|
goto cleanup;
|
|
}
|
|
break;
|
|
default:
|
|
IPCOM_LOG1(ERR, "ipssh_sftp_clt_get :: unexpected sftp msg received: %d", pkt_type);
|
|
goto cleanup;
|
|
}
|
|
|
|
switch(pkt_type)
|
|
{
|
|
case IPSSH_FXP_DATA:
|
|
if (ipssh_buffer_get_uint(ssh_conn->recv_plain_buf, &data_len)
|
|
|| ipcom_buffer_len(ssh_conn->recv_plain_buf) != data_len)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_sftp_clt_get :: failed to unpack FXP_DATA msg");
|
|
goto cleanup;
|
|
}
|
|
if (data_len > read_req->len)
|
|
{
|
|
IPCOM_LOG2(WARNING, "ipssh_sftp_clt_get :: received more bytes (%d) than requested (%d)",
|
|
data_len, read_req->len);
|
|
data_len = read_req->len;
|
|
}
|
|
if (func->lseek_cb(fd, read_req->offset, IP_SEEK_SET) == -1)
|
|
{
|
|
IPCOM_LOG2(ERR, "ipssh_sftp_clt_get :: lseek_cb failed, offset: %llu, errno: %d",
|
|
(long long unsigned int)read_req->offset, ipcom_errno);
|
|
goto cleanup;
|
|
}
|
|
if (func->write_cb(fd, (char*)ipcom_buffer_start_ptr(ssh_conn->recv_plain_buf), data_len) != (int)data_len)
|
|
{
|
|
IPCOM_LOG1(ERR, "ipssh_sftp_clt_get :: failed to write to file, errno:%d", ipcom_errno);
|
|
goto cleanup;
|
|
}
|
|
if (data_len == read_req->len)
|
|
{
|
|
/* The entire request was returned, dispatch a new request */
|
|
read_req->len = ipssh_get_sftp_req_len(channel, IPSSH_SRV2CLT, data_len);
|
|
read_req->req_id = ++channel->data.sftp.req_id;
|
|
IP_U64_COPY(read_req->offset, offset);
|
|
IP_U64_ADD32(offset, read_req->len);
|
|
if(ipssh_send_fxp_read(channel, handle, handle_len, read_req) != IPCOM_SUCCESS)
|
|
goto cleanup;
|
|
/* Dispatch another request? */
|
|
if (max_reqs > ipcom_list_length(&pending_reqs))
|
|
{
|
|
if (ipssh_sftp_clt_dispatch_read_req(channel,
|
|
&pending_reqs,
|
|
IP_NULL,
|
|
handle,
|
|
handle_len,
|
|
++channel->data.sftp.req_id,
|
|
offset,
|
|
read_len) != IPCOM_SUCCESS)
|
|
{
|
|
IPCOM_LOG3(ERR, "ipssh_sftp_clt_get :: failed to dispatch read request %d: local path: %s, remote path: %s",
|
|
ipcom_list_length(&pending_reqs), local_path, remote_path);
|
|
goto cleanup;
|
|
}
|
|
IP_U64_ADD32(offset, read_len);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Only a fraction of the request was returned, request the remaining part */
|
|
read_req->len -= data_len;
|
|
read_req->req_id = ++channel->data.sftp.req_id;
|
|
IP_U64_ADD32(read_req->offset, data_len);
|
|
if(ipssh_send_fxp_read(channel, handle, handle_len, read_req) != IPCOM_SUCCESS)
|
|
goto cleanup;
|
|
|
|
/* Lower the requested read size in case we are requesting larger 'chunks' than the server can deliver. */
|
|
if (data_len < read_len)
|
|
{
|
|
if (data_len >= 4096)
|
|
read_len = data_len;
|
|
else
|
|
read_len = 4096; /* Don't allow the read size to become unreasonable small */
|
|
|
|
}
|
|
|
|
}
|
|
(void)ipcom_buffer_consume(ssh_conn->recv_plain_buf, data_len);
|
|
break;
|
|
|
|
case IPSSH_FXP_STATUS:
|
|
if (ipssh_buffer_get_uint(ssh_conn->recv_plain_buf, &error))
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_sftp_clt_get :: failed to unpack FXP_STATUS msg 2");
|
|
goto cleanup;
|
|
}
|
|
switch(error)
|
|
{
|
|
case IPSSH_FX_EOF:
|
|
ipcom_list_remove(&read_req->list);
|
|
ipcom_free(read_req);
|
|
break;
|
|
default:
|
|
(void)ipssh_send_fxp_close(channel, handle, handle_len);
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto cleanup;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
IP_PANIC(); /* We should never get here */
|
|
goto cleanup;
|
|
}
|
|
} while (ipcom_list_length(&pending_reqs) > 0);
|
|
|
|
rc = ipssh_send_fxp_close(channel, handle, handle_len);
|
|
|
|
cleanup:
|
|
for (read_req = (Ipssh_sftp_clt_read_req*)ipcom_list_first(&pending_reqs);
|
|
read_req;
|
|
read_req = (Ipssh_sftp_clt_read_req*)ipcom_list_first(&pending_reqs))
|
|
{
|
|
ipcom_list_remove(&read_req->list);
|
|
ipcom_free(read_req);
|
|
}
|
|
func->close_cb(fd); /*lint !e522*/
|
|
if(rc != IPCOM_SUCCESS)
|
|
func->unlink_cb(local_path); /*lint !e522*/
|
|
if(handle)
|
|
ipcom_free(handle);
|
|
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_sftp_clt_put_flags
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_PUBLIC Ip_err
|
|
ipssh_sftp_clt_put_flags(Ipssh_conn* ssh_conn, const char* local_path, const char* remote_path, Ip_u32 remote_path_flags)
|
|
{
|
|
Ip_err rc = IPCOM_ERR_FAILED;
|
|
char abs_remote_path[IPSSH_SFTP_MAX_PATH];
|
|
Ip_u8 pkt_type;
|
|
Ipssh_channel* channel;
|
|
Ip_u32 req_id;
|
|
Ip_u32 error;
|
|
Ip_u8* handle = IP_NULL;
|
|
Ip_u32 handle_len;
|
|
int fd;
|
|
Ipssh_sftp_func_cb* func;
|
|
Ip_u64 offset;
|
|
Ipcom_buffer* pkt = IP_NULL;
|
|
struct Ip_stat file_attr;
|
|
|
|
if(!ssh_conn || ssh_conn->conn_state != IPSSH_CONN_STATE_CLT_CONNECTED || !ssh_conn->data.clt.channel
|
|
|| !local_path || !remote_path)
|
|
{
|
|
IP_PANIC2();
|
|
return IPCOM_ERR_INVALID_ARG;
|
|
}
|
|
|
|
channel = ssh_conn->data.clt.channel;
|
|
|
|
func = ipssh_get_sftp_func_cb(local_path);
|
|
if(!func)
|
|
return IPCOM_ERR_FAILED;
|
|
|
|
if(ipssh_make_abs_path(channel->data.sftp.cwd, remote_path, abs_remote_path, IPSSH_SFTP_MAX_PATH) != IPCOM_SUCCESS)
|
|
return IPCOM_ERR_INVALID_ARG;
|
|
|
|
/* Open local file */
|
|
fd = func->open_cb(local_path, IP_O_RDONLY, 0);
|
|
if(fd == -1)
|
|
{
|
|
IPCOM_LOG1(ERR, "ipssh_sftp_clt_put_flags :: failed to open local file: %s", local_path);
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
|
|
ipcom_memset(&file_attr, 0, sizeof(file_attr));
|
|
file_attr.st_mode = 0644;
|
|
if(ipssh_send_fxp_open(channel, abs_remote_path, remote_path_flags,
|
|
IPSSH_FILEXFER_ATTR_PERMISSIONS, &file_attr))
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_sftp_clt_put_flags :: ipssh_send_fxp_open() failed");
|
|
goto cleanup;
|
|
}
|
|
|
|
if(ipssh_read_sftp_msg(channel))
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_sftp_clt_put_flags :: ipssh_read_sftp_msg() failed");
|
|
goto cleanup;
|
|
}
|
|
|
|
if(ipcom_buffer_get_char(ssh_conn->recv_plain_buf, &pkt_type))
|
|
goto cleanup;
|
|
|
|
switch(pkt_type)
|
|
{
|
|
case IPSSH_FXP_HANDLE:
|
|
if(ipssh_buffer_get_uint(ssh_conn->recv_plain_buf, &req_id)
|
|
|| (handle = ipssh_buffer_get_sshbuf(ssh_conn->recv_plain_buf, &handle_len)) == IP_NULL)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_sftp_clt_put_flags :: failed to unpack FXP_HANDLE msg");
|
|
goto cleanup;
|
|
}
|
|
break;
|
|
|
|
case IPSSH_FXP_STATUS:
|
|
if(ipssh_buffer_get_uint(ssh_conn->recv_plain_buf, &req_id)
|
|
|| ipssh_buffer_get_uint(ssh_conn->recv_plain_buf, &error))
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_sftp_clt_put_flags :: failed to unpack FXP_STATUS msg");
|
|
goto cleanup;
|
|
}
|
|
switch(error)
|
|
{
|
|
case IPSSH_FX_NO_SUCH_FILE:
|
|
rc = IPCOM_ERR_NOT_FOUND;
|
|
goto cleanup;
|
|
case IPSSH_FX_PERMISSION_DENIED:
|
|
rc = IPCOM_ERR_PERMISSION_DENIED;
|
|
goto cleanup;
|
|
default:
|
|
goto cleanup;
|
|
}
|
|
|
|
default:
|
|
IPCOM_LOG1(ERR, "ipssh_sftp_clt_put_flags :: unexpected sftp msg received: %d", pkt_type);
|
|
goto cleanup;
|
|
}
|
|
|
|
/* File opened, start writing */
|
|
IP_U64_CLEAR(offset);
|
|
while(1)
|
|
{
|
|
Ip_u32 req_len;
|
|
Ip_s32 bytes_read;
|
|
Ip_u8* len_ptr;
|
|
int min_win_size;
|
|
|
|
if(pkt)
|
|
ipcom_buffer_free(pkt);
|
|
|
|
/* pkt overhead: sftp msg len (4), sftp msg type (1), req_id (4), handle_len+4, offset (8), len 4 */
|
|
min_win_size = 4+1+4+handle_len+4+8+4;
|
|
min_win_size++; /* We must be able to send at least one byte of file content */
|
|
ipssh_sftp_clt_check_ch_win(channel, min_win_size);
|
|
req_len = ipssh_get_sftp_req_len(channel, IPSSH_CLT2SRV, 0);
|
|
req_len = IP_MIN(req_len, IPSSH_CH_MAX_PKT-5);
|
|
ip_assert(req_len > 0);
|
|
pkt = ipssh_buffer_new_sftp_pkt(req_len, IPSSH_FXP_WRITE);
|
|
if(!pkt)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_sftp_clt_put_flags :: failed to allocate FXP_WRITE msg");
|
|
goto cleanup;
|
|
}
|
|
channel->data.sftp.req_id++;
|
|
if(ipssh_buffer_put_uint(pkt, channel->data.sftp.req_id)
|
|
|| ipssh_buffer_put_sshbuf(pkt, handle, handle_len)
|
|
|| ipssh_buffer_put_u64(pkt, offset))
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_sftp_clt_put_flags :: failed to pack msg");
|
|
goto cleanup;
|
|
}
|
|
|
|
len_ptr = ipcom_buffer_end_ptr(pkt);
|
|
if(ipssh_buffer_put_uint(pkt, 0)) /* Dummy length */
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_sftp_clt_put_flags :: failed to pack msg 2");
|
|
goto cleanup;
|
|
}
|
|
ip_assert(ipcom_buffer_capacity(pkt) > IPSSH_MAX_PAD);
|
|
|
|
bytes_read = (Ip_s32)func->read_cb(fd, (char*)ipcom_buffer_end_ptr(pkt), ipcom_buffer_capacity(pkt)-IPSSH_MAX_PAD);
|
|
if(bytes_read < 0)
|
|
{
|
|
IPCOM_LOG3(ERR, "ipssh_sftp_clt_put_flags :: read_cb failed: offset hi:%d, lo:%d, req_len",
|
|
IP_U64_GETHI(offset), IP_U64_GETLO(offset), ipcom_buffer_capacity(pkt));
|
|
goto cleanup;
|
|
}
|
|
else if(bytes_read == 0)
|
|
{
|
|
rc = ipssh_send_fxp_close(channel, handle, handle_len);
|
|
goto cleanup;
|
|
}
|
|
else
|
|
{
|
|
(void)ipcom_buffer_decr_cap(pkt, (Ip_u32)bytes_read);
|
|
IP_U64_ADD32(offset, bytes_read);
|
|
IP_SET_32ON8(len_ptr, ip_htonl(bytes_read));
|
|
if(ipssh_send_fxp_msg(channel, pkt) != IPCOM_SUCCESS)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_sftp_clt_put_flags :: ipssh_send_fxp_msg failed for FXP_WRITE msg");
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
if(ipssh_read_sftp_msg(channel))
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_sftp_clt_put_flags :: ipssh_read_sftp_msg() failed");
|
|
goto cleanup;
|
|
}
|
|
|
|
if(ipcom_buffer_get_char(ssh_conn->recv_plain_buf, &pkt_type))
|
|
goto cleanup;
|
|
switch(pkt_type)
|
|
{
|
|
case IPSSH_FXP_STATUS:
|
|
if(ipssh_buffer_get_uint(ssh_conn->recv_plain_buf, &req_id)
|
|
|| ipssh_buffer_get_uint(ssh_conn->recv_plain_buf, &error))
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_sftp_clt_put_flags :: failed to unpack FXP_STATUS msg 2");
|
|
goto cleanup;
|
|
}
|
|
switch(error)
|
|
{
|
|
case IPSSH_FX_OK:
|
|
break;
|
|
default:
|
|
IPCOM_LOG1(ERR, "ipssh_sftp_clt_put_flags :: FXP_STATUS error=%d", error);
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto cleanup;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
IPCOM_LOG1(ERR, "ipssh_sftp_clt_put_flags :: unexpected sftp msg received: %d", pkt_type);
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
cleanup:
|
|
(void)func->close_cb(fd);
|
|
if(pkt)
|
|
ipcom_buffer_free(pkt);
|
|
if(handle)
|
|
ipcom_free(handle);
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_sftp_clt_put
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_PUBLIC Ip_err
|
|
ipssh_sftp_clt_put(Ipssh_conn* ssh_conn, const char* local_path, const char* remote_path)
|
|
{
|
|
return ipssh_sftp_clt_put_flags(ssh_conn, local_path, remote_path, IPSSH_FXF_WRITE|IPSSH_FXF_CREAT|IPSSH_FXF_TRUNC);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_sftp_clt_opendir
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_PUBLIC void*
|
|
ipssh_sftp_clt_opendir(struct Ipssh_conn_st* ssh_conn, const char* path)
|
|
{
|
|
Ipssh_channel* channel;
|
|
char abs_path[IPSSH_SFTP_MAX_PATH];
|
|
Ipssh_sftp_clt_dir_handle* handle;
|
|
Ip_u32 req_id;
|
|
Ip_u32 status;
|
|
Ip_u8 pkt_type;
|
|
|
|
|
|
IPCOM_LOG1(DEBUG, "ipssh_sftp_clt_opendir :: path=%s", path);
|
|
|
|
if(!ssh_conn || ssh_conn->conn_state != IPSSH_CONN_STATE_CLT_CONNECTED
|
|
|| !ssh_conn->data.clt.channel
|
|
|| !path || ipcom_strlen(path) > IPSSH_SFTP_MAX_PATH)
|
|
{
|
|
IP_PANIC2();
|
|
return IP_NULL;
|
|
}
|
|
channel = ssh_conn->data.clt.channel;
|
|
|
|
if(ipssh_make_abs_path(channel->data.sftp.cwd, path, abs_path, sizeof(abs_path)) != IPCOM_SUCCESS)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_sftp_clt_opendir :: ipssh_make_abs_path failed");
|
|
return IP_NULL;
|
|
}
|
|
|
|
handle = ipcom_malloc(sizeof(Ipssh_sftp_clt_dir_handle));
|
|
if(!handle)
|
|
{
|
|
return IP_NULL;
|
|
}
|
|
ipcom_memset(handle, 0, sizeof(Ipssh_sftp_clt_dir_handle));
|
|
handle->magic = IPSSH_SFTP_CLT_HANDLE_MAGIC;
|
|
|
|
if(ipssh_send_fxp_opendir(channel, abs_path) != IPCOM_SUCCESS)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_sftp_clt_opendir :: ipssh_send_fxp_opendir failed");
|
|
goto cleanup;
|
|
}
|
|
|
|
if(ipssh_read_sftp_msg(channel))
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_sftp_clt_opendir :: ipssh_read_sftp_msg() failed");
|
|
goto cleanup;
|
|
}
|
|
|
|
if(ipcom_buffer_get_char(ssh_conn->recv_plain_buf, &pkt_type))
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_sftp_clt_opendir :: failed to unpack msg");
|
|
goto cleanup;
|
|
}
|
|
switch(pkt_type)
|
|
{
|
|
case IPSSH_FXP_HANDLE:
|
|
if(ipssh_buffer_get_uint(ssh_conn->recv_plain_buf, &req_id)
|
|
|| (handle->ptr=ipssh_buffer_get_sshbuf(ssh_conn->recv_plain_buf, &handle->len)) == IP_NULL)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_sftp_clt_opendir :: failed to unpack msg");
|
|
goto cleanup;
|
|
}
|
|
break;
|
|
|
|
case IPSSH_FXP_STATUS:
|
|
if(ipssh_buffer_get_uint(ssh_conn->recv_plain_buf, &req_id)
|
|
|| ipssh_buffer_get_uint(ssh_conn->recv_plain_buf, &status))
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_sftp_clt_opendir :: failed to unpack STATUS msg");
|
|
}
|
|
else
|
|
IPCOM_LOG1(ERR, "ipssh_sftp_clt_opendir :: FXP_REALPATH failed, status: %d", status);
|
|
|
|
goto cleanup;
|
|
|
|
default:
|
|
IP_PANIC();
|
|
goto cleanup;
|
|
}
|
|
|
|
return handle;
|
|
|
|
cleanup:
|
|
if(handle)
|
|
ipcom_free(handle);
|
|
|
|
return IP_NULL;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_sftp_clt_readdir
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_PUBLIC Ipssh_dirent*
|
|
ipssh_sftp_clt_readdir(struct Ipssh_conn_st* ssh_conn, void* handle)
|
|
{
|
|
Ipssh_channel* channel;
|
|
Ipssh_sftp_clt_dir_handle* dir_handle = (Ipssh_sftp_clt_dir_handle*) handle;
|
|
Ip_u32 req_id;
|
|
Ip_u32 status;
|
|
Ip_u32 attr_flags;
|
|
Ip_u8 pkt_type;
|
|
char* filename = IP_NULL;
|
|
char* longname = IP_NULL;
|
|
Ipssh_dirent* ret = IP_NULL;
|
|
|
|
if(!ssh_conn || ssh_conn->conn_state != IPSSH_CONN_STATE_CLT_CONNECTED
|
|
|| !ssh_conn->data.clt.channel || !dir_handle || dir_handle->magic != IPSSH_SFTP_CLT_HANDLE_MAGIC)
|
|
{
|
|
IP_PANIC2();
|
|
return IP_NULL;
|
|
}
|
|
channel = ssh_conn->data.clt.channel;
|
|
ipcom_memset(&dir_handle->ret, 0, sizeof(dir_handle->ret));
|
|
|
|
if(dir_handle->count == 0)
|
|
{
|
|
if(ipssh_send_fxp_readdir(channel, dir_handle->ptr, dir_handle->len) != IPCOM_SUCCESS)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_sftp_clt_readdir :: ipssh_send_fxp_readdir() failed");
|
|
return IP_NULL;
|
|
}
|
|
|
|
if(ipssh_read_sftp_msg(channel))
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_sftp_clt_readdir :: ipssh_read_sftp_msg() failed");
|
|
goto cleanup;
|
|
}
|
|
|
|
if(ipcom_buffer_get_char(ssh_conn->recv_plain_buf, &pkt_type))
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_sftp_clt_readdir :: failed to unpack msg");
|
|
goto cleanup;
|
|
}
|
|
|
|
switch(pkt_type)
|
|
{
|
|
case IPSSH_FXP_NAME:
|
|
if(ipssh_buffer_get_uint(ssh_conn->recv_plain_buf, &req_id)
|
|
|| ipssh_buffer_get_uint(ssh_conn->recv_plain_buf, &dir_handle->count))
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_sftp_clt_readdir :: failed to unpack FXP_NAME msg");
|
|
goto cleanup;
|
|
}
|
|
if(dir_handle->count == 0)
|
|
goto cleanup;
|
|
dir_handle->pkt = ssh_conn->recv_plain_buf;
|
|
ssh_conn->recv_plain_buf = IP_NULL;
|
|
break;
|
|
|
|
case IPSSH_FXP_STATUS:
|
|
if(ipssh_buffer_get_uint(ssh_conn->recv_plain_buf, &req_id)
|
|
|| ipssh_buffer_get_uint(ssh_conn->recv_plain_buf, &status))
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_sftp_clt_readdir :: failed to unpack FXP_STATUS msg");
|
|
goto cleanup;
|
|
}
|
|
return IP_NULL;
|
|
|
|
default:
|
|
IP_PANIC();
|
|
return IP_NULL;
|
|
}
|
|
}
|
|
|
|
if((filename=ipssh_buffer_get_sshstr(dir_handle->pkt)) == IP_NULL
|
|
|| (longname=ipssh_buffer_get_sshstr(dir_handle->pkt)) == IP_NULL
|
|
|| ipssh_buffer_get_uint(dir_handle->pkt, &attr_flags) != IPCOM_SUCCESS
|
|
|| ipssh_unpack_attr(dir_handle->pkt, attr_flags, &dir_handle->ret.attr) != IPCOM_SUCCESS)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_sftp_clt_readdir :: failed to unpack FXP_NAME msg");
|
|
dir_handle->count = 0;
|
|
goto cleanup;
|
|
}
|
|
dir_handle->count--;
|
|
ipcom_strncpy(dir_handle->ret.name, filename, sizeof(dir_handle->ret.name) - 1);
|
|
ipcom_strncpy(dir_handle->ret.longname, longname, sizeof(dir_handle->ret.longname) - 1);
|
|
ret = &dir_handle->ret;
|
|
|
|
cleanup:
|
|
if(dir_handle->count == 0)
|
|
{
|
|
if(dir_handle->pkt != IP_NULL)
|
|
{
|
|
ipcom_buffer_free(dir_handle->pkt);
|
|
dir_handle->pkt = IP_NULL;
|
|
}
|
|
}
|
|
if(filename)
|
|
ipcom_free(filename);
|
|
if(longname)
|
|
ipcom_free(longname);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_sftp_clt_closedir
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_PUBLIC Ip_err
|
|
ipssh_sftp_clt_closedir(struct Ipssh_conn_st* ssh_conn, void* handle)
|
|
{
|
|
Ip_err rc;
|
|
Ipssh_sftp_clt_dir_handle* dir_handle = (Ipssh_sftp_clt_dir_handle*) handle;
|
|
|
|
if(!ssh_conn || ssh_conn->conn_state != IPSSH_CONN_STATE_CLT_CONNECTED
|
|
|| !ssh_conn->data.clt.channel || !dir_handle || dir_handle->magic != IPSSH_SFTP_CLT_HANDLE_MAGIC)
|
|
{
|
|
IP_PANIC2();
|
|
return IPCOM_ERR_INVALID_ARG;
|
|
}
|
|
|
|
rc = ipssh_send_fxp_close(ssh_conn->data.clt.channel, dir_handle->ptr, dir_handle->len);
|
|
ipcom_free(dir_handle->ptr);
|
|
if(dir_handle->pkt)
|
|
ipcom_buffer_free(dir_handle->pkt);
|
|
ipcom_free(dir_handle);
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_sftp_clt_close
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_PUBLIC Ip_err
|
|
ipssh_sftp_clt_close(Ipssh_conn* ssh_conn)
|
|
{
|
|
if(!ssh_conn)
|
|
{
|
|
IP_PANIC2();
|
|
return IPCOM_ERR_INVALID_ARG;
|
|
}
|
|
|
|
ipssh_conn_free(ssh_conn);
|
|
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_sftp_clt_get_cwd
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_PUBLIC Ip_err
|
|
ipssh_sftp_clt_get_cwd(Ipssh_conn* ssh_conn, char* buf, int buf_len)
|
|
{
|
|
if(ssh_conn->conn_state != IPSSH_CONN_STATE_CLT_CONNECTED || !ssh_conn->data.clt.channel
|
|
|| !buf)
|
|
{
|
|
IP_PANIC2();
|
|
return IPCOM_ERR_INVALID_ARG;
|
|
}
|
|
|
|
if(buf_len > (int)ipcom_strlen(ssh_conn->data.clt.channel->data.sftp.cwd))
|
|
{
|
|
ipcom_strcpy(buf, ssh_conn->data.clt.channel->data.sftp.cwd);
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
else
|
|
return IPCOM_ERR_INVALID_ARG;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_sftp_clt_get_realpath
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_PUBLIC Ip_err
|
|
ipssh_sftp_clt_get_realpath(Ipssh_conn* ssh_conn, const char* path, char* buf, int buf_len)
|
|
{
|
|
Ipssh_channel* channel;
|
|
Ip_u8 pkt_type;
|
|
Ip_u32 count;
|
|
Ip_u32 req_id;
|
|
Ip_u32 attr_flags;
|
|
char* filename = IP_NULL;
|
|
char* longname = IP_NULL;
|
|
struct Ip_stat file_attr;
|
|
Ip_u32 status;
|
|
Ip_err rc = IPCOM_ERR_FAILED;
|
|
|
|
if(!ssh_conn || ssh_conn->conn_state != IPSSH_CONN_STATE_CLT_CONNECTED || !ssh_conn->data.clt.channel)
|
|
{
|
|
IP_PANIC2();
|
|
return IPCOM_ERR_INVALID_ARG;
|
|
}
|
|
channel = ssh_conn->data.clt.channel;
|
|
|
|
if(ipssh_send_fxp_realpath(channel, path) != IPCOM_SUCCESS)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_sftp_clt_get_realpath :: ipssh_send_fxp_realpath() failed");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
if(ipssh_read_sftp_msg(channel))
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_sftp_clt_get_realpath :: ipssh_read_sftp_msg() failed");
|
|
goto cleanup;
|
|
}
|
|
|
|
if(ipcom_buffer_get_char(ssh_conn->recv_plain_buf, &pkt_type))
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_sftp_clt_get_realpath :: failed to unpack msg");
|
|
goto cleanup;
|
|
}
|
|
switch(pkt_type)
|
|
{
|
|
case IPSSH_FXP_NAME:
|
|
if(ipssh_buffer_get_uint(ssh_conn->recv_plain_buf, &req_id)
|
|
|| ipssh_buffer_get_uint(ssh_conn->recv_plain_buf, &count)
|
|
|| (filename=ipssh_buffer_get_sshstr(ssh_conn->recv_plain_buf)) == IP_NULL
|
|
|| (longname=ipssh_buffer_get_sshstr(ssh_conn->recv_plain_buf)) == IP_NULL
|
|
|| ipssh_buffer_get_uint(ssh_conn->recv_plain_buf, &attr_flags)
|
|
|| ipssh_unpack_attr(ssh_conn->recv_plain_buf, attr_flags, &file_attr))
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_sftp_clt_get_realpath :: failed to unpack FXP_NAME msg");
|
|
goto cleanup;
|
|
}
|
|
if(buf_len < (int)ipcom_strlen(filename))
|
|
{
|
|
rc = IPCOM_ERR_INVALID_ARG;
|
|
goto cleanup;
|
|
}
|
|
ipcom_strcpy(buf, filename);
|
|
break;
|
|
|
|
case IPSSH_FXP_STATUS:
|
|
if(ipssh_buffer_get_uint(ssh_conn->recv_plain_buf, &req_id)
|
|
|| ipssh_buffer_get_uint(ssh_conn->recv_plain_buf, &status))
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_sftp_clt_get_realpath :: failed to unpack STATUS msg");
|
|
}
|
|
else
|
|
IPCOM_LOG1(ERR, "ipssh_sftp_clt_get_realpath :: FXP_REALPATH failed, status: %d", status);
|
|
|
|
goto cleanup;
|
|
|
|
default:
|
|
IPCOM_LOG1(ERR, "ipssh_sftp_clt_get_realpath :: unexpected sftp msg received, %d", pkt_type);
|
|
IP_PANIC();
|
|
goto cleanup;
|
|
}
|
|
|
|
rc = IPCOM_SUCCESS;
|
|
|
|
cleanup:
|
|
if(filename)
|
|
ipcom_free(filename);
|
|
if(longname)
|
|
ipcom_free(longname);
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_sftp_clt_mkdir
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_PUBLIC Ip_err
|
|
ipssh_sftp_clt_mkdir(struct Ipssh_conn_st* ssh_conn, const char* path, Ip_mode_t mode)
|
|
{
|
|
Ipssh_channel* channel;
|
|
char abs_path[IPSSH_SFTP_MAX_PATH];
|
|
Ip_u8 pkt_type;
|
|
Ip_u32 req_id;
|
|
Ip_u32 attr_flags;
|
|
struct Ip_stat file_attr;
|
|
Ip_u32 status;
|
|
Ipcom_buffer *pkt;
|
|
Ip_err rc = IPCOM_ERR_FAILED;
|
|
|
|
if(!ssh_conn || ssh_conn->conn_state != IPSSH_CONN_STATE_CLT_CONNECTED || !ssh_conn->data.clt.channel || !path)
|
|
{
|
|
IP_PANIC2();
|
|
return IPCOM_ERR_INVALID_ARG;
|
|
}
|
|
channel = ssh_conn->data.clt.channel;
|
|
|
|
if(ipssh_make_abs_path(channel->data.sftp.cwd, path, abs_path, IPSSH_SFTP_MAX_PATH) != IPCOM_SUCCESS)
|
|
return IPCOM_ERR_INVALID_ARG;
|
|
|
|
pkt = ipssh_buffer_new_sftp_pkt(32+ipcom_strlen(abs_path), IPSSH_FXP_MKDIR);
|
|
if(!pkt)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_sftp_clt_mkdir :: out of memory");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
channel->data.sftp.req_id++;
|
|
(void)ipssh_buffer_put_int(pkt, channel->data.sftp.req_id);
|
|
(void)ipssh_buffer_put_sshstr(pkt, abs_path);
|
|
ipcom_memset(&file_attr, 0, sizeof(file_attr));
|
|
file_attr.st_mode = mode;
|
|
attr_flags = IPSSH_FILEXFER_ATTR_PERMISSIONS;
|
|
(void)ipssh_pack_attr(pkt, &file_attr, attr_flags);
|
|
|
|
if(ipssh_send_fxp_msg(channel, pkt))
|
|
goto cleanup;
|
|
|
|
/* Read reply */
|
|
if(ipssh_read_sftp_msg(channel))
|
|
goto cleanup;
|
|
if(ipcom_buffer_get_char(channel->ssh_conn->recv_plain_buf, &pkt_type))
|
|
goto cleanup;
|
|
if(pkt_type == IPSSH_FXP_STATUS)
|
|
{
|
|
if(ipssh_buffer_get_uint(channel->ssh_conn->recv_plain_buf, &req_id)
|
|
|| ipssh_buffer_get_uint(channel->ssh_conn->recv_plain_buf, &status))
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_sftp_clt_unlink :: failed to unpack FXP_STATUS msg");
|
|
goto cleanup;
|
|
}
|
|
switch(status)
|
|
{
|
|
case IPSSH_FX_OK:
|
|
rc = IPCOM_SUCCESS;
|
|
break;
|
|
case IPSSH_FX_PERMISSION_DENIED:
|
|
rc = IPCOM_ERR_PERMISSION_DENIED;
|
|
break;
|
|
}
|
|
}
|
|
|
|
cleanup:
|
|
if(pkt)
|
|
ipcom_buffer_free(pkt);
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_sftp_clt_rmdir
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_PUBLIC Ip_err
|
|
ipssh_sftp_clt_rmdir(struct Ipssh_conn_st* ssh_conn, const char* path)
|
|
{
|
|
Ipssh_channel* channel;
|
|
char abs_path[IPSSH_SFTP_MAX_PATH];
|
|
Ip_u8 pkt_type;
|
|
Ip_u32 req_id;
|
|
Ip_u32 status;
|
|
Ipcom_buffer *pkt;
|
|
Ip_err rc = IPCOM_ERR_FAILED;
|
|
|
|
if(!ssh_conn || ssh_conn->conn_state != IPSSH_CONN_STATE_CLT_CONNECTED || !ssh_conn->data.clt.channel || !path)
|
|
{
|
|
IP_PANIC2();
|
|
return IPCOM_ERR_INVALID_ARG;
|
|
}
|
|
channel = ssh_conn->data.clt.channel;
|
|
|
|
if(ipssh_make_abs_path(channel->data.sftp.cwd, path, abs_path, IPSSH_SFTP_MAX_PATH) != IPCOM_SUCCESS)
|
|
return IPCOM_ERR_INVALID_ARG;
|
|
|
|
pkt = ipssh_buffer_new_sftp_pkt(32+ipcom_strlen(abs_path), IPSSH_FXP_RMDIR);
|
|
if(!pkt)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_sftp_clt_rmdir :: out of memory");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
channel->data.sftp.req_id++;
|
|
(void)ipssh_buffer_put_int(pkt, channel->data.sftp.req_id);
|
|
(void)ipssh_buffer_put_sshstr(pkt, abs_path);
|
|
|
|
if(ipssh_send_fxp_msg(channel, pkt))
|
|
goto cleanup;
|
|
|
|
/* Read reply */
|
|
if(ipssh_read_sftp_msg(channel))
|
|
goto cleanup;
|
|
if(ipcom_buffer_get_char(channel->ssh_conn->recv_plain_buf, &pkt_type))
|
|
goto cleanup;
|
|
if(pkt_type == IPSSH_FXP_STATUS)
|
|
{
|
|
if(ipssh_buffer_get_uint(channel->ssh_conn->recv_plain_buf, &req_id)
|
|
|| ipssh_buffer_get_uint(channel->ssh_conn->recv_plain_buf, &status))
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_sftp_clt_unlink :: failed to unpack FXP_STATUS msg");
|
|
goto cleanup;
|
|
}
|
|
switch(status)
|
|
{
|
|
case IPSSH_FX_OK:
|
|
rc = IPCOM_SUCCESS;
|
|
break;
|
|
case IPSSH_FX_PERMISSION_DENIED:
|
|
rc = IPCOM_ERR_PERMISSION_DENIED;
|
|
break;
|
|
}
|
|
}
|
|
|
|
cleanup:
|
|
if(pkt)
|
|
ipcom_buffer_free(pkt);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_sftp_clt_chdir
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_PUBLIC Ip_err
|
|
ipssh_sftp_clt_chdir(struct Ipssh_conn_st* ssh_conn, const char* path)
|
|
{
|
|
char abs_path[IPSSH_SFTP_MAX_PATH];
|
|
|
|
if(ssh_conn->conn_state != IPSSH_CONN_STATE_CLT_CONNECTED || !ssh_conn->data.clt.channel || !path)
|
|
{
|
|
IP_PANIC2();
|
|
return IPCOM_ERR_INVALID_ARG;
|
|
}
|
|
if(ipssh_make_abs_path(ssh_conn->data.clt.channel->data.sftp.cwd, path, abs_path, sizeof(abs_path)) != IPCOM_SUCCESS)
|
|
return IPCOM_ERR_INVALID_ARG;
|
|
|
|
if(ipssh_sftp_clt_get_realpath(ssh_conn, abs_path, abs_path, IPSSH_SFTP_MAX_PATH) != IPCOM_SUCCESS)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_sftp_clt_chdir :: ipssh_sftp_clt_get_realpath() failed");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
ipcom_strcpy(ssh_conn->data.clt.channel->data.sftp.cwd, abs_path);
|
|
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_sftp_clt_unlink
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_PUBLIC Ip_err
|
|
ipssh_sftp_clt_unlink(struct Ipssh_conn_st* ssh_conn, const char* path)
|
|
{
|
|
Ip_err rc = IPCOM_ERR_FAILED;
|
|
char abs_path[IPSSH_SFTP_MAX_PATH];
|
|
Ipcom_buffer* pkt;
|
|
Ip_u8 pkt_type;
|
|
Ip_u32 req_id;
|
|
Ip_u32 status;
|
|
Ipssh_channel* channel;
|
|
|
|
if(ssh_conn->conn_state != IPSSH_CONN_STATE_CLT_CONNECTED || !ssh_conn->data.clt.channel || !path)
|
|
{
|
|
IP_PANIC2();
|
|
return IPCOM_ERR_INVALID_ARG;
|
|
}
|
|
channel = ssh_conn->data.clt.channel;
|
|
|
|
if(ipssh_make_abs_path(channel->data.sftp.cwd, path, abs_path, IPSSH_SFTP_MAX_PATH) != IPCOM_SUCCESS)
|
|
return IPCOM_ERR_INVALID_ARG;
|
|
|
|
pkt = ipssh_buffer_new_sftp_pkt(32+ipcom_strlen(abs_path), IPSSH_FXP_REMOVE);
|
|
if(!pkt)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_send_fxp_remove :: out of memory");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
channel->data.sftp.req_id++;
|
|
(void)ipssh_buffer_put_int(pkt, channel->data.sftp.req_id);
|
|
(void)ipssh_buffer_put_sshstr(pkt, abs_path);
|
|
|
|
if(ipssh_send_fxp_msg(channel, pkt))
|
|
goto cleanup;
|
|
|
|
/* Read reply */
|
|
if(ipssh_read_sftp_msg(channel))
|
|
goto cleanup;
|
|
if(ipcom_buffer_get_char(channel->ssh_conn->recv_plain_buf, &pkt_type))
|
|
goto cleanup;
|
|
if(pkt_type == IPSSH_FXP_STATUS)
|
|
{
|
|
if(ipssh_buffer_get_uint(channel->ssh_conn->recv_plain_buf, &req_id)
|
|
|| ipssh_buffer_get_uint(channel->ssh_conn->recv_plain_buf, &status))
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_sftp_clt_unlink :: failed to unpack FXP_STATUS msg");
|
|
goto cleanup;
|
|
}
|
|
switch(status)
|
|
{
|
|
case IPSSH_FX_OK:
|
|
rc = IPCOM_SUCCESS;
|
|
break;
|
|
case IPSSH_FX_NO_SUCH_FILE:
|
|
rc = IPCOM_ERR_NOT_FOUND;
|
|
break;
|
|
case IPSSH_FX_PERMISSION_DENIED:
|
|
rc = IPCOM_ERR_PERMISSION_DENIED;
|
|
break;
|
|
}
|
|
}
|
|
|
|
cleanup:
|
|
if(pkt)
|
|
ipcom_buffer_free(pkt);
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_sftp_clt_set_key
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_PUBLIC Ip_err
|
|
ipssh_sftp_clt_set_key(struct Ipssh_conn_st* ssh_conn, EVP_PKEY* key)
|
|
{
|
|
if(!ssh_conn || !key || (key->type != NID_dsa && key->type != NID_rsaEncryption))
|
|
{
|
|
IP_PANIC2();
|
|
return IPCOM_ERR_INVALID_ARG;
|
|
}
|
|
|
|
ssh_conn->data.clt.key = key;
|
|
ssh_conn->data.clt.key->references++;
|
|
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_sftp_clt_set_hostb_key
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_PUBLIC Ip_err
|
|
ipssh_sftp_clt_set_hostb_key(struct Ipssh_conn_st* ssh_conn, EVP_PKEY* key)
|
|
{
|
|
if(!ssh_conn || !key || (key->type != NID_dsa && key->type != NID_rsaEncryption))
|
|
{
|
|
IP_PANIC2();
|
|
return IPCOM_ERR_INVALID_ARG;
|
|
}
|
|
|
|
ssh_conn->data.clt.host_key = key;
|
|
ssh_conn->data.clt.host_key->references++;
|
|
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_sftp_clt_set_userid
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_PUBLIC Ip_err
|
|
ipssh_sftp_clt_set_userid(Ipssh_conn* ssh_conn, const char* user)
|
|
{
|
|
if(!ssh_conn || !user || ipcom_strlen(user)>sizeof(ssh_conn->data.clt.userid))
|
|
{
|
|
IP_PANIC2();
|
|
return IPCOM_ERR_INVALID_ARG;
|
|
}
|
|
|
|
ipcom_strcpy(ssh_conn->data.clt.userid, user);
|
|
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_sftp_clt_set_userid_pw
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_PUBLIC Ip_err
|
|
ipssh_sftp_clt_set_pw(Ipssh_conn* ssh_conn, const char* pw)
|
|
{
|
|
if(!ssh_conn || !pw || ipcom_strlen(pw)>sizeof(ssh_conn->data.clt.pw))
|
|
{
|
|
IP_PANIC2();
|
|
return IPCOM_ERR_INVALID_ARG;
|
|
}
|
|
|
|
ipcom_strcpy(ssh_conn->data.clt.pw, pw);
|
|
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_sftp_clt_rename
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_PUBLIC Ip_err
|
|
ipssh_sftp_clt_rename(struct Ipssh_conn_st* ssh_conn, const char* oldpath, const char* newpath)
|
|
{
|
|
Ip_err rc = IPCOM_ERR_FAILED;
|
|
char old_abs_path[IPSSH_SFTP_MAX_PATH];
|
|
char new_abs_path[IPSSH_SFTP_MAX_PATH];
|
|
Ipcom_buffer* pkt;
|
|
Ip_u8 pkt_type;
|
|
Ip_u32 req_id;
|
|
Ip_u32 status;
|
|
Ipssh_channel* channel;
|
|
|
|
if(ssh_conn->conn_state != IPSSH_CONN_STATE_CLT_CONNECTED || !ssh_conn->data.clt.channel || !oldpath || !newpath)
|
|
{
|
|
IP_PANIC2();
|
|
return IPCOM_ERR_INVALID_ARG;
|
|
}
|
|
channel = ssh_conn->data.clt.channel;
|
|
|
|
if(ipssh_make_abs_path(channel->data.sftp.cwd, oldpath, old_abs_path, IPSSH_SFTP_MAX_PATH) != IPCOM_SUCCESS)
|
|
return IPCOM_ERR_INVALID_ARG;
|
|
if(ipssh_make_abs_path(channel->data.sftp.cwd, newpath, new_abs_path, IPSSH_SFTP_MAX_PATH) != IPCOM_SUCCESS)
|
|
return IPCOM_ERR_INVALID_ARG;
|
|
|
|
pkt = ipssh_buffer_new_sftp_pkt(32+ipcom_strlen(old_abs_path)+ipcom_strlen(new_abs_path), IPSSH_FXP_RENAME);
|
|
if(!pkt)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_send_fxp_rename :: out of memory");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
channel->data.sftp.req_id++;
|
|
(void)ipssh_buffer_put_int(pkt, channel->data.sftp.req_id);
|
|
(void)ipssh_buffer_put_sshstr(pkt, old_abs_path);
|
|
(void)ipssh_buffer_put_sshstr(pkt, new_abs_path);
|
|
|
|
if(ipssh_send_fxp_msg(channel, pkt))
|
|
goto cleanup;
|
|
|
|
/* Read reply */
|
|
if(ipssh_read_sftp_msg(channel))
|
|
goto cleanup;
|
|
if(ipcom_buffer_get_char(channel->ssh_conn->recv_plain_buf, &pkt_type))
|
|
goto cleanup;
|
|
if(pkt_type == IPSSH_FXP_STATUS)
|
|
{
|
|
if(ipssh_buffer_get_uint(channel->ssh_conn->recv_plain_buf, &req_id)
|
|
|| ipssh_buffer_get_uint(channel->ssh_conn->recv_plain_buf, &status))
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_sftp_clt_rename :: failed to unpack FXP_STATUS msg");
|
|
goto cleanup;
|
|
}
|
|
switch(status)
|
|
{
|
|
case IPSSH_FX_OK:
|
|
rc = IPCOM_SUCCESS;
|
|
break;
|
|
case IPSSH_FX_NO_SUCH_FILE:
|
|
rc = IPCOM_ERR_NOT_FOUND;
|
|
break;
|
|
case IPSSH_FX_PERMISSION_DENIED:
|
|
rc = IPCOM_ERR_PERMISSION_DENIED;
|
|
break;
|
|
}
|
|
}
|
|
|
|
cleanup:
|
|
if(pkt)
|
|
ipcom_buffer_free(pkt);
|
|
|
|
return rc;
|
|
}
|
|
|
|
#else
|
|
int ipssh_sftp_clt_empty_file;
|
|
#endif /* IPSSH_USE_SFTP_CLT */
|
|
/*
|
|
****************************************************************************
|
|
* END OF FILE
|
|
****************************************************************************
|
|
*/
|
|
|