2523 lines
76 KiB
C
2523 lines
76 KiB
C
/*
|
|
******************************************************************************
|
|
* SOURCE FILE
|
|
*
|
|
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipssh_sftp.c,v $ $Revision: 1.89.10.13 $
|
|
* $Source: /home/interpeak/CVSRoot/ipssh/src/ipssh_sftp.c,v $
|
|
* $Author: yli10 $ $Date: 2019-09-06 06:45:53 $
|
|
* $State: Exp $ $Locker: $
|
|
*
|
|
* INTERPEAK_COPYRIGHT_STRING
|
|
* Design and implementation by Roger Boden <roger@interpeak.se>
|
|
******************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 1 DESCRIPTION
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 2 CONFIGURATION
|
|
****************************************************************************
|
|
*/
|
|
|
|
#define IPCOM_USE_CLIB_PROTO
|
|
#include <ipssh_config.h>
|
|
|
|
#ifdef IPSSH_USE_SFTP
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 3 INCLUDE FILES
|
|
****************************************************************************
|
|
*/
|
|
|
|
#include "ipssh_h.h"
|
|
#include "ipssh.h"
|
|
#include "ipssh_transport.h"
|
|
#include "ipssh_connection.h"
|
|
#include "ipssh_sftp.h"
|
|
#include "ipssh_buffer.h"
|
|
|
|
#include <ipcom_clib.h>
|
|
#include <ipcom_type.h>
|
|
#include <ipcom_cstyle.h>
|
|
#include <ipcom_time.h>
|
|
#include <ipcom_err.h>
|
|
#include <ipcom_buffer.h>
|
|
#include <ipcom_syslog.h>
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 4 EXTERN PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 5 DEFINES
|
|
****************************************************************************
|
|
*/
|
|
#define IPSSH_SFTP_READDIR_BUF_SIZE 4*1024
|
|
|
|
#define IPSSH_FILE_HANDLE 1
|
|
#define IPSSH_DIR_HANDLE 2
|
|
|
|
#define IPSSH_S_IFDIR 0x4000
|
|
#define IPSSH_S_IFREG 0x8000
|
|
/*
|
|
****************************************************************************
|
|
* 6 TYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/* External handle, given to client */
|
|
struct Ipssh_sftp_ext_handle_st
|
|
{
|
|
Ip_u32 id;
|
|
Ip_u8 cookie[8];
|
|
Ip_u8 mac[8];
|
|
};
|
|
typedef struct Ipssh_sftp_ext_handle_st Ipssh_sftp_ext_handle;
|
|
|
|
struct Ipssh_sftp_int_handle_st
|
|
{
|
|
Ipcom_list list;
|
|
Ip_u32 type;
|
|
Ip_u32 id;
|
|
char* path;
|
|
Ip_s32 eof;
|
|
IP_DIR* dir;
|
|
Ip_fd fd;
|
|
Ip_u64 read_pos;
|
|
Ip_u64 write_pos;
|
|
Ipssh_sftp_func_cb* funcs;
|
|
};
|
|
typedef struct Ipssh_sftp_int_handle_st Ipssh_sftp_int_handle;
|
|
|
|
typedef Ipcom_list Ipssh_sftp_handle_map;
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 7 LOCAL PROTOTYPES
|
|
****************************************************************************
|
|
*/
|
|
|
|
/* sftp message handlers */
|
|
IP_GLOBAL Ip_err ipssh_msg_fxp_init(Ipssh_channel* channel, Ipcom_buffer* pkt_buf);
|
|
IP_GLOBAL Ip_err ipssh_msg_fxp_opendir(Ipssh_channel* channel, Ipcom_buffer* pkt_buf);
|
|
IP_GLOBAL Ip_err ipssh_msg_fxp_readdir(Ipssh_channel* channel,
|
|
Ipcom_buffer* pkt_buf);
|
|
IP_GLOBAL Ip_err ipssh_msg_fxp_open(Ipssh_channel* channel,
|
|
Ipcom_buffer* pkt_buf);
|
|
IP_GLOBAL Ip_err ipssh_msg_fxp_lstat(Ipssh_channel* channel,
|
|
Ipcom_buffer* pkt_buf);
|
|
IP_GLOBAL Ip_err ipssh_msg_fxp_setstat(Ipssh_channel* channel,
|
|
Ipcom_buffer* pkt_buf);
|
|
IP_GLOBAL Ip_err ipssh_msg_fxp_read(Ipssh_channel* channel,
|
|
Ipcom_buffer* pkt_buf);
|
|
IP_GLOBAL Ip_err ipssh_msg_fxp_write(Ipssh_channel* channel,
|
|
Ipcom_buffer* pkt_buf);
|
|
IP_GLOBAL Ip_err ipssh_msg_fxp_realpath(Ipssh_channel* channel,
|
|
Ipcom_buffer* pkt_buf);
|
|
IP_GLOBAL Ip_err ipssh_msg_fxp_close(Ipssh_channel* channel,
|
|
Ipcom_buffer* pkt_buf);
|
|
IP_GLOBAL Ip_err ipssh_msg_fxp_eof(Ipssh_channel* channel,
|
|
Ipcom_buffer* pkt_buf);
|
|
IP_GLOBAL Ip_err ipssh_msg_fxp_remove(Ipssh_channel* channel,
|
|
Ipcom_buffer* pkt_buf);
|
|
IP_GLOBAL Ip_err ipssh_msg_fxp_mkdir(Ipssh_channel* channel,
|
|
Ipcom_buffer* pkt_buf);
|
|
IP_GLOBAL Ip_err ipssh_msg_fxp_rmdir(Ipssh_channel* channel,
|
|
Ipcom_buffer* pkt_buf);
|
|
IP_GLOBAL Ip_err ipssh_msg_fxp_rename(Ipssh_channel* channel,
|
|
Ipcom_buffer* pkt_buf);
|
|
|
|
/* Send message functions */
|
|
IP_GLOBAL Ip_err ipssh_send_fxp_version(Ipssh_channel* channel);
|
|
IP_GLOBAL Ip_err ipssh_send_fxp_name(Ipssh_channel* channel, Ip_u32 req_id, char* path);
|
|
IP_GLOBAL Ip_err ipssh_send_fxp_handle(Ipssh_channel* channel, Ip_u32 req_id, Ipssh_sftp_ext_handle* handle, Ip_u32 handle_len);
|
|
|
|
|
|
IP_STATIC Ip_err ipssh_sftp_msg_handler(Ipssh_channel* channel, Ipcom_buffer* msg);
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 8 DATA
|
|
****************************************************************************
|
|
*/
|
|
|
|
IP_STATIC Ip_u8 ipssh_handle_cookie[8] = { 4,7,1,7,4,7,1,7 };
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 9 LOCAL FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_get_file_priv
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC void
|
|
ipssh_get_file_priv(Ip_mode_t mode, char *p)
|
|
{
|
|
/* print type */
|
|
if(IP_S_ISDIR(mode)) /* directory */
|
|
*p++ = 'd';
|
|
#ifdef IP_S_ISCHR
|
|
else if(IP_S_ISCHR(mode)) /* character special */
|
|
*p++ = 'c';
|
|
#endif
|
|
#ifdef IP_S_ISBLK
|
|
else if(IP_S_ISBLK(mode)) /* block special */
|
|
*p++ = 'b';
|
|
#endif
|
|
else if(IP_S_ISREG(mode)) /* regular */
|
|
*p++ = '-';
|
|
#ifdef IP_S_ISLNK
|
|
else if(IP_S_ISLNK(mode)) /* symbolic link */
|
|
*p++ = 'l';
|
|
#endif
|
|
else /* unknown */
|
|
*p++ = '?';
|
|
|
|
/* usr */
|
|
if(mode & IP_S_IRUSR)
|
|
*p++ = 'r';
|
|
else
|
|
*p++ = '-';
|
|
if(mode & IP_S_IWUSR)
|
|
*p++ = 'w';
|
|
else
|
|
*p++ = '-';
|
|
if(mode & IP_S_IXUSR)
|
|
*p++ = 'x';
|
|
else
|
|
*p++ = '-';
|
|
|
|
/* group */
|
|
if (mode & IP_S_IRGRP)
|
|
*p++ = 'r';
|
|
else
|
|
*p++ = '-';
|
|
if (mode & IP_S_IWGRP)
|
|
*p++ = 'w';
|
|
else
|
|
*p++ = '-';
|
|
if(mode & IP_S_IXGRP)
|
|
*p++ = 'x';
|
|
else
|
|
*p++ = '-';
|
|
|
|
/* other */
|
|
if (mode & IP_S_IROTH)
|
|
*p++ = 'r';
|
|
else
|
|
*p++ = '-';
|
|
if (mode & IP_S_IWOTH)
|
|
*p++ = 'w';
|
|
else
|
|
*p++ = '-';
|
|
if(mode & IP_S_IXOTH)
|
|
*p++ = 'x';
|
|
else
|
|
*p++ = '-';
|
|
|
|
*p = '\0';
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_make_long_name
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC void
|
|
ipssh_make_long_name(const char* path, const char* filename,
|
|
struct Ip_stat* file_stats, char* long_list)
|
|
{
|
|
char *tmp_path;
|
|
char file_priv[11];
|
|
struct Ip_tm *tm;
|
|
|
|
tmp_path = ipcom_malloc(ipcom_strlen(path) + 1 + ipcom_strlen(filename)+1);
|
|
if(!tmp_path)
|
|
{
|
|
ipcom_strcpy(long_list,filename);
|
|
return;
|
|
}
|
|
|
|
ipcom_strcpy(tmp_path, path);
|
|
ipcom_strcat(tmp_path, "/");
|
|
ipcom_strcat(tmp_path, filename);
|
|
ipssh_get_file_priv(file_stats->st_mode, file_priv);
|
|
|
|
tm = (struct Ip_tm *)ipcom_localtime((void *)&(file_stats->st_mtime)); /*lint !e64*/
|
|
if (tm != IP_NULL)
|
|
ipcom_sprintf(long_list, "%10s %3d %-4ld %-4ld %-8ld %04d-%02d-%02d %02d:%02d %s",
|
|
file_priv, 1, file_stats->st_uid, file_stats->st_gid,
|
|
file_stats->st_size, tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
|
|
tm->tm_hour, tm->tm_min, filename);
|
|
|
|
ipcom_free(tmp_path);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_pack_stat_data
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC Ip_err
|
|
ipssh_pack_stat_data(Ipcom_buffer* pkt, struct Ip_stat* stat)
|
|
{
|
|
return ipssh_pack_attr(pkt, stat, IPSSH_FILEXFER_ATTR_SIZE|
|
|
IPSSH_FILEXFER_ATTR_ACMODTIME|
|
|
IPSSH_FILEXFER_ATTR_PERMISSIONS|
|
|
IPSSH_FILEXFER_ATTR_UIDGID);
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_conv_flags
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC Ip_u32
|
|
ipssh_conv_flags(Ip_u32 flags)
|
|
{
|
|
Ip_u32 ret = 0;
|
|
|
|
if((flags & IPSSH_FXF_READ) && (flags & IPSSH_FXF_WRITE))
|
|
ret |= IP_O_RDWR;
|
|
if(flags & IPSSH_FXF_READ)
|
|
ret |= IP_O_RDONLY;
|
|
if(flags & IPSSH_FXF_WRITE)
|
|
ret |= IP_O_WRONLY;
|
|
if(flags & IPSSH_FXF_APPEND)
|
|
ret |= IP_O_APPEND;
|
|
if(flags & IPSSH_FXF_CREAT)
|
|
ret |= IP_O_CREAT;
|
|
#ifdef IP_O_EXCL
|
|
if(flags & IPSSH_FXF_EXCL)
|
|
ret |= IP_O_EXCL;
|
|
#endif
|
|
#ifdef IP_O_TRUNC
|
|
if(flags & IPSSH_FXF_TRUNC)
|
|
ret |= IP_O_TRUNC;
|
|
#endif
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_make_ext_int_paths
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC Ip_err
|
|
ipssh_make_ext_int_paths(char* org_path,
|
|
char* start_dir,
|
|
Ipcom_shell_ctx* sh_ctx,
|
|
char** ext_path,
|
|
char** int_path)
|
|
{
|
|
char* session_root_dir = IP_NULL;
|
|
Ip_err ret;
|
|
char start_dir_buf[IPSSH_SFTP_MAX_PATH];
|
|
|
|
if (ipcom_strcmp(org_path, ".") != 0 && org_path[0] != '/')
|
|
return IPCOM_ERR_INVALID_ARG;
|
|
|
|
ret = ipcom_shell_ctx_get(sh_ctx, IPSSH_SFTP_ROOT_DIR, (Ip_u8**)&session_root_dir, IP_NULL);
|
|
if (ret != IPCOM_SUCCESS && ret != IPCOM_ERR_NOT_FOUND)
|
|
return ret;
|
|
|
|
if (session_root_dir)
|
|
IPCOM_LOG1(DEBUG, "ipssh_make_ext_int_path :: session root dir: %s", session_root_dir);
|
|
IPCOM_LOG1(DEBUG, "ipssh_make_ext_int_path :: start dir: %s", start_dir);
|
|
|
|
if (!ipcom_normpath(org_path, org_path))
|
|
return IPCOM_ERR_FAILED;
|
|
|
|
if (ipcom_strcmp(start_dir, ".") == 0 || ipcom_strcmp(start_dir, "./") == 0)
|
|
{
|
|
if (!ipcom_getcwd(start_dir_buf, sizeof(start_dir_buf)))
|
|
{
|
|
IPCOM_LOG1(DEBUG, "ipssh_make_ext_int_path :: ipcom_getcwd() failed (errno=%d)", ipcom_errno);
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
if (!ipcom_normpath(start_dir_buf, start_dir_buf))
|
|
return IPCOM_ERR_FAILED;
|
|
start_dir = start_dir_buf;
|
|
}
|
|
|
|
ret = ipcom_shell_ctx_get(sh_ctx, IPSSH_SFTP_ROOT_DIR, (Ip_u8**)&session_root_dir, IP_NULL);
|
|
if (ret != IPCOM_SUCCESS && ret != IPCOM_ERR_NOT_FOUND)
|
|
return ret;
|
|
if (session_root_dir)
|
|
if (!ipcom_normpath(session_root_dir, session_root_dir))
|
|
{
|
|
ipcom_free(session_root_dir);
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
if (ipcom_strcmp(org_path, ".") == 0)
|
|
{
|
|
if (session_root_dir)
|
|
{
|
|
/* If session_root_dir and start_dir are the same, return "/" as external path */
|
|
if (ipcom_strlen(session_root_dir) == ipcom_strlen(start_dir) &&
|
|
ipcom_strcmp(session_root_dir, start_dir) == 0)
|
|
{
|
|
*int_path = ipcom_strdup(start_dir);
|
|
if (ext_path)
|
|
*ext_path = ipcom_strdup("/");
|
|
}
|
|
|
|
/* If start dir is not a sub-directory of session root dir, make session root dir our start dir */
|
|
else if (ipcom_strlen(session_root_dir) > ipcom_strlen(start_dir) ||
|
|
ipcom_strncmp(session_root_dir, start_dir, ipcom_strlen(session_root_dir)))
|
|
{
|
|
*int_path = ipcom_strdup(session_root_dir);
|
|
if (ext_path)
|
|
*ext_path = ipcom_strdup("/");
|
|
}
|
|
else
|
|
{
|
|
*int_path = ipcom_strdup(start_dir);
|
|
if (ext_path)
|
|
{
|
|
*ext_path = ipcom_malloc(IP_MAX(ipcom_strlen(start_dir),ipcom_strlen(session_root_dir))+1);
|
|
if (!*ext_path)
|
|
goto cleanup;
|
|
|
|
/* 'Peel off' common path of session_root_dir from start_dir */
|
|
ipcom_strcpy(*ext_path, start_dir+ipcom_strlen(session_root_dir));
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (ext_path)
|
|
*ext_path = ipcom_strdup(start_dir);
|
|
*int_path = ipcom_strdup(start_dir);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (session_root_dir)
|
|
{
|
|
if (ext_path)
|
|
*ext_path = ipcom_strdup(org_path);
|
|
*int_path = ipcom_malloc(ipcom_strlen(session_root_dir)+ipcom_strlen(org_path)+2);
|
|
|
|
if ((ext_path && !*ext_path) || !*int_path)
|
|
goto cleanup;
|
|
|
|
ipcom_strcpy(*int_path, session_root_dir);
|
|
if ((*int_path)[ipcom_strlen(session_root_dir)] != '/' && org_path[0] != '/')
|
|
ipcom_strcat(*int_path, "/");
|
|
ipcom_strcat(*int_path, org_path);
|
|
}
|
|
else
|
|
{
|
|
if (ext_path)
|
|
*ext_path = ipcom_strdup(org_path);
|
|
*int_path = ipcom_strdup(org_path);
|
|
|
|
if ((ext_path && !*ext_path) || !*int_path)
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
if (session_root_dir)
|
|
{
|
|
ipcom_free(session_root_dir);
|
|
session_root_dir = IP_NULL;
|
|
}
|
|
if ((!ext_path || *ext_path) && *int_path)
|
|
return IPCOM_SUCCESS;
|
|
|
|
cleanup:
|
|
if (ext_path && *ext_path)
|
|
ipcom_free(*ext_path);
|
|
if (*int_path)
|
|
ipcom_free(*int_path);
|
|
if (session_root_dir)
|
|
ipcom_free(session_root_dir);
|
|
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_sftp_srv_pkt_dispatch
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC Ip_err
|
|
ipssh_sftp_pkt_dispatch(Ipssh_channel* channel, Ipcom_buffer* pkt)
|
|
{
|
|
switch(channel->type)
|
|
{
|
|
#ifdef IPSSH_USE_SFTP_CLT
|
|
case IPSSH_CH_TYPE_SFTP_CLT:
|
|
return ipssh_sftp_clt_pkt_dispatch(channel, pkt);
|
|
#endif
|
|
case IPSSH_CH_TYPE_SFTP_SRV:
|
|
return ipssh_sftp_srv_pkt_dispatch(channel, pkt);
|
|
default:
|
|
IP_PANIC();
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_sftp_msg_handler
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC Ip_err
|
|
ipssh_sftp_msg_handler(Ipssh_channel* channel, Ipcom_buffer* msg)
|
|
{
|
|
Ip_u32 sftp_msg_len;
|
|
Ip_s32 rc;
|
|
|
|
if(!channel->data.sftp.msg) /* Is this the beginning of a fresh sftp message? */
|
|
{
|
|
if (ipcom_buffer_len(msg) < 4)
|
|
{
|
|
/* Since we don't have received enough bytes to read the packet length, we
|
|
* allocate a buffer that will fit a max-size packet. */
|
|
sftp_msg_len = IPSSH_CH_MAX_PKT + 128;
|
|
channel->data.sftp.msg_len = 0;
|
|
}
|
|
else
|
|
{
|
|
if(ipssh_buffer_get_uint(msg, &sftp_msg_len))
|
|
return IPCOM_ERR_FAILED;
|
|
if(sftp_msg_len >= IPSSH_CH_MAX_PKT + 128)
|
|
{
|
|
IPCOM_LOG1(ERR, "ipssh_sftp_msg_handler :: the packet's message length (%d) is more than max-size",
|
|
sftp_msg_len);
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
channel->data.sftp.msg_len = sftp_msg_len;
|
|
}
|
|
if(sftp_msg_len > ipcom_buffer_len(msg))
|
|
{
|
|
/* We have only received a fragment of an sftp message */
|
|
channel->data.sftp.msg = ipcom_buffer_new(sftp_msg_len);
|
|
if(!channel->data.sftp.msg)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_sftp_msg_handler :: out of memory");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
(void)ipcom_buffer_put(channel->data.sftp.msg, ipcom_buffer_start_ptr(msg), ipcom_buffer_len(msg));
|
|
IPCOM_LOG2(DEBUG2, "ipssh_sftp_msg_handler :: incomplete packet: sftp_msg_len=%d, ch_data_len=%d",
|
|
sftp_msg_len, ipcom_buffer_len(msg));
|
|
(void)ipcom_buffer_consume(msg, ipcom_buffer_len(msg));
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
rc = ipssh_sftp_pkt_dispatch(channel, msg);
|
|
}
|
|
else /* We have a packet fragment already */
|
|
{
|
|
Ip_size_t len;
|
|
Ip_size_t bytes_missing;
|
|
IPCOM_LOG3(DEBUG2, "ipssh_sftp_msg_handler :: incomplete packet: sftp_msg_len=%d, pos=%d, ch_data_len=%d",
|
|
channel->data.sftp.msg->alloc, ipcom_buffer_len(channel->data.sftp.msg), ipcom_buffer_len(msg));
|
|
|
|
if (channel->data.sftp.msg_len == 0)
|
|
{
|
|
Ip_size_t oldlen;
|
|
oldlen = ipcom_buffer_len(channel->data.sftp.msg);
|
|
if (oldlen >= 4)
|
|
return IPCOM_ERR_FAILED;
|
|
|
|
/*It mostly cannot occur*/
|
|
if (4 > (oldlen + ipcom_buffer_len(msg)))
|
|
{
|
|
(void)ipcom_buffer_put(channel->data.sftp.msg, ipcom_buffer_start_ptr(msg), ipcom_buffer_len(msg));
|
|
(void)ipcom_buffer_consume(msg, ipcom_buffer_len(msg));
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
/* We only get the complete sftp packet length */
|
|
(void)ipcom_buffer_put(channel->data.sftp.msg, ipcom_buffer_start_ptr(msg), 4-oldlen);
|
|
(void)ipcom_buffer_consume(msg, 4-oldlen);
|
|
if (ipssh_buffer_get_uint(channel->data.sftp.msg, &channel->data.sftp.msg_len))
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
bytes_missing = channel->data.sftp.msg_len-ipcom_buffer_len(channel->data.sftp.msg);
|
|
len = IP_MIN(bytes_missing, ipcom_buffer_len(msg)); /*lint !e666 */
|
|
(void)ipcom_buffer_put(channel->data.sftp.msg, ipcom_buffer_start_ptr(msg), len);
|
|
(void)ipcom_buffer_consume(msg, len);
|
|
|
|
if(channel->data.sftp.msg_len == 0 ||
|
|
ipcom_buffer_len(channel->data.sftp.msg) < (Ip_u32)channel->data.sftp.msg_len)
|
|
return IPCOM_SUCCESS; /* We do not have a complete sftp message at this point */
|
|
|
|
/* Right, now we have a complete sftp message */
|
|
rc = ipssh_sftp_pkt_dispatch(channel, channel->data.sftp.msg);
|
|
ipcom_buffer_free(channel->data.sftp.msg);
|
|
channel->data.sftp.msg = IP_NULL;
|
|
}
|
|
|
|
/* Did we receive more than one sftp message? */
|
|
if(rc == IPCOM_SUCCESS && ipcom_buffer_len(msg) > 0)
|
|
{
|
|
/* We have an additional packet */
|
|
rc = ipssh_sftp_msg_handler(channel, msg);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_map_insert
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC Ip_err
|
|
ipssh_map_insert(Ipssh_sftp_handle_map* sftp_map, Ipssh_sftp_int_handle* new_entry)
|
|
{
|
|
Ipcom_list* item;
|
|
Ipcom_list* map = (Ipcom_list*) sftp_map;
|
|
|
|
IPCOM_LOG2(DEBUG2, "ipssh_map_insert :: path = %s, id=%d",
|
|
new_entry->path ? new_entry->path : "null", new_entry->id);
|
|
|
|
/* Check that the ID is not already inserted */
|
|
for(item = ipcom_list_first(map); item; item = ipcom_list_next(item))
|
|
{
|
|
Ipssh_sftp_int_handle* entry = (Ipssh_sftp_int_handle*) item;
|
|
if(entry->id == new_entry->id)
|
|
{
|
|
IPCOM_LOG1(ERR, "ipssh_map_insert :: id already in map: %d", new_entry->id);
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
}
|
|
|
|
ipcom_list_insert_first(map, (Ipcom_list*) new_entry);
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_map_lookup
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC Ipssh_sftp_int_handle*
|
|
ipssh_map_lookup(Ipssh_sftp_handle_map* sftp_map, Ip_u32 id)
|
|
{
|
|
Ipcom_list* item;
|
|
Ipcom_list* map = (Ipcom_list*) sftp_map;
|
|
|
|
IPCOM_LOG1(DEBUG2, "ipssh_map_lookup :: id=%d", id);
|
|
for(item = ipcom_list_first(map); item; item = ipcom_list_next(item))
|
|
{
|
|
Ipssh_sftp_int_handle* entry = (Ipssh_sftp_int_handle*) item;
|
|
|
|
if(entry->id == id)
|
|
return entry;
|
|
}
|
|
|
|
IPCOM_LOG1(ERR, "ipssh_map_lookup :: failed to find id=%d", id);
|
|
return IP_NULL;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_map_remove
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC Ip_err
|
|
ipssh_map_remove(Ipssh_sftp_handle_map* sftp_map, Ip_u32 id)
|
|
{
|
|
Ipcom_list* item;
|
|
Ipcom_list* map = (Ipcom_list*) sftp_map;
|
|
|
|
IPCOM_LOG1(DEBUG2, "ipssh_map_remove :: id=%d", id);
|
|
for(item = ipcom_list_first(map); item; item = ipcom_list_next(item))
|
|
{
|
|
Ipssh_sftp_int_handle* entry = (Ipssh_sftp_int_handle*) item;
|
|
|
|
if(entry->id == id)
|
|
{
|
|
IPCOM_LOG2(DEBUG2, "ipssh_map_remove :: id=%d, path=%s", id, entry->path?entry->path:"null");
|
|
ipcom_list_remove(item);
|
|
if(entry->type == IPSSH_DIR_HANDLE )
|
|
{
|
|
if(entry->funcs->closedir_cb)
|
|
entry->funcs->closedir_cb(entry->dir); /*lint !e522 */
|
|
else
|
|
IP_PANIC();
|
|
}
|
|
else
|
|
{
|
|
if(entry->funcs->close_cb)
|
|
entry->funcs->close_cb(entry->fd); /*lint !e522 */
|
|
else
|
|
IP_PANIC();
|
|
}
|
|
if(entry->path)
|
|
ipcom_free(entry->path);
|
|
ipcom_free(entry);
|
|
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
}
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_create_handle
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC Ip_err
|
|
ipssh_create_handle(Ipssh_sftp_ext_handle** handle, Ip_u32* len)
|
|
{
|
|
static Ip_u32 id = 1;
|
|
Ipssh_sftp_ext_handle* tmp_handle;
|
|
|
|
if(!(tmp_handle = ipcom_malloc(sizeof(Ipssh_sftp_ext_handle))) )
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_create_handle :: out of memory");
|
|
return IP_NULL;
|
|
}
|
|
|
|
tmp_handle->id = id++;
|
|
|
|
ipcom_memcpy(tmp_handle->cookie, ipssh_handle_cookie, sizeof(tmp_handle->cookie));
|
|
|
|
*handle = tmp_handle;
|
|
*len = sizeof(Ipssh_sftp_ext_handle);
|
|
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_validate_handle
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_STATIC Ip_err
|
|
ipssh_validate_handle(Ipssh_sftp_ext_handle* handle, Ip_u32 len)
|
|
{
|
|
if(len != sizeof(Ipssh_sftp_ext_handle) ||
|
|
ipcom_memcmp(handle->cookie, ipssh_handle_cookie, sizeof(handle->cookie)) )
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_validate_handle :: invalid handle");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
****************************************************************************
|
|
* 10 PUBLIC FUNCTIONS
|
|
****************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_send_fxp_msg
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipssh_send_fxp_msg(Ipssh_channel* channel, Ipcom_buffer* msg)
|
|
{
|
|
Ip_u32 sftp_msg_len;
|
|
|
|
sftp_msg_len = (Ip_u32)ipcom_buffer_len(msg)-18;
|
|
IPSSH_SET_32_PTR(ipcom_buffer_ptr2pos(msg, 14), sftp_msg_len); /*lint !e666*/
|
|
|
|
return ipssh_send_channel_data_msg(channel, msg);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_sftp_srv_pkt_dispatch
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipssh_sftp_srv_pkt_dispatch(Ipssh_channel* channel, Ipcom_buffer* pkt)
|
|
{
|
|
Ip_u32 req_id;
|
|
Ip_u8 pkt_type;
|
|
Ip_err rc;
|
|
|
|
if(ipcom_buffer_get_char(pkt, &pkt_type) != IPCOM_SUCCESS)
|
|
return IPCOM_ERR_FAILED;
|
|
|
|
IPCOM_LOG2(DEBUG2, "ipssh_sftp_srv_pkt_dispatch :: pkt type: %d, data_len:%d",
|
|
pkt_type, ipcom_buffer_len(pkt));
|
|
|
|
/* check the SFTP user access */
|
|
if(ipssh_sftp_check_access_cb(channel->ssh_conn->user, IPSSH_FXP_ACCESS, IP_NULL, IP_NULL) != IPCOM_SUCCESS) /*lint !e644*/
|
|
{
|
|
/* Unpack message */
|
|
(void)ipssh_buffer_get_uint(pkt, &req_id);
|
|
rc = ipssh_send_fxp_status(channel, req_id, IPSSH_FX_PERMISSION_DENIED);
|
|
IPCOM_LOG3(ERR, "ipssh_sftp_srv_pkt_dispatch :: unknown pkt type: %d, ch_id: %d, req_id: %d",
|
|
pkt_type, channel->my_ch_id, req_id);
|
|
return rc;
|
|
}
|
|
|
|
switch(pkt_type)
|
|
{
|
|
case IPSSH_FXP_INIT:
|
|
rc = ipssh_msg_fxp_init(channel, pkt);
|
|
break;
|
|
case IPSSH_FXP_OPENDIR:
|
|
rc = ipssh_msg_fxp_opendir(channel, pkt);
|
|
break;
|
|
case IPSSH_FXP_READDIR:
|
|
rc = ipssh_msg_fxp_readdir(channel, pkt);
|
|
break;
|
|
case IPSSH_FXP_CLOSE:
|
|
rc = ipssh_msg_fxp_close(channel, pkt);
|
|
break;
|
|
case IPSSH_FXP_OPEN:
|
|
rc = ipssh_msg_fxp_open(channel, pkt);
|
|
break;
|
|
case IPSSH_FXP_LSTAT:
|
|
case IPSSH_FXP_STAT:
|
|
rc = ipssh_msg_fxp_lstat(channel, pkt);
|
|
break;
|
|
case IPSSH_FXP_SETSTAT:
|
|
rc = ipssh_msg_fxp_setstat(channel, pkt);
|
|
break;
|
|
case IPSSH_FXP_REALPATH:
|
|
rc = ipssh_msg_fxp_realpath(channel, pkt);
|
|
break;
|
|
case IPSSH_FXP_READ:
|
|
rc = ipssh_msg_fxp_read(channel, pkt);
|
|
break;
|
|
case IPSSH_FXP_WRITE:
|
|
rc = ipssh_msg_fxp_write(channel, pkt);
|
|
break;
|
|
case IPSSH_FXP_REMOVE:
|
|
rc = ipssh_msg_fxp_remove(channel, pkt);
|
|
break;
|
|
case IPSSH_FXP_RMDIR:
|
|
rc = ipssh_msg_fxp_rmdir(channel, pkt);
|
|
break;
|
|
case IPSSH_FXP_MKDIR:
|
|
rc = ipssh_msg_fxp_mkdir(channel, pkt);
|
|
break;
|
|
case IPSSH_FXP_RENAME:
|
|
rc = ipssh_msg_fxp_rename(channel, pkt);
|
|
break;
|
|
|
|
/* Unsupported messages */
|
|
case IPSSH_FXP_FSTAT:
|
|
case IPSSH_FXP_FSETSTAT:
|
|
case IPSSH_FXP_READLINK:
|
|
case IPSSH_FXP_SYMLINK:
|
|
case IPSSH_FXP_EXTENDED:
|
|
case IPSSH_FXP_EXTENDED_REPLY:
|
|
if(ipssh_buffer_get_uint(pkt, &req_id) != IPCOM_SUCCESS)
|
|
{
|
|
ipcom_buffer_reset(pkt);
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
else
|
|
{
|
|
IPCOM_LOG3(ERR, "ipssh_sftp_srv_pkt_dispatch :: pkt type not supported: %d, ch_id: %d, req_id: %d",
|
|
pkt_type, channel->my_ch_id, req_id);
|
|
ipcom_buffer_reset(pkt);
|
|
return ipssh_send_fxp_status(channel, req_id, IPSSH_FX_OP_UNSUPPORTED);
|
|
}
|
|
|
|
/* Messages a server shouldn't receive */
|
|
case IPSSH_FXP_ATTRS:
|
|
case IPSSH_FXP_VERSION:
|
|
case IPSSH_FXP_STATUS:
|
|
case IPSSH_FXP_NAME:
|
|
|
|
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_srv_pkt_dispatch :: unknown pkt type: %d, ch_id: %d, req_id: %d",
|
|
pkt_type, channel->my_ch_id, req_id);
|
|
}
|
|
IP_PANIC();
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_mode_ipcom2ssh
|
|
*===========================================================================
|
|
* Description: Converts file mode bits from IPCOM values to SSH values.
|
|
*/
|
|
IP_GLOBAL Ip_mode_t
|
|
ipssh_mode_ipcom2ssh(Ip_mode_t mode)
|
|
{
|
|
Ip_mode_t ret;
|
|
|
|
/* Set access mode bits */
|
|
ret = mode & 0x1FF;
|
|
|
|
if(IP_S_ISDIR(mode))
|
|
ret |= IPSSH_S_IFDIR;
|
|
if(IP_S_ISREG(mode))
|
|
ret |= IPSSH_S_IFREG;
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_mode_ssh2ipcom
|
|
*===========================================================================
|
|
* Description: Converts file mode bits from SSH values to IPCOM values.
|
|
*/
|
|
IP_GLOBAL Ip_mode_t
|
|
ipssh_mode_ssh2ipcom(Ip_mode_t mode)
|
|
{
|
|
Ip_mode_t ret;
|
|
|
|
/* Set access mode bits */
|
|
ret = mode & 0x1FF;
|
|
|
|
if(mode & IPSSH_S_IFDIR)
|
|
ret |= IP_S_IFDIR;
|
|
if(mode & IPSSH_S_IFREG)
|
|
ret |= IP_S_IFREG;
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_unpack_attr
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipssh_unpack_attr(Ipcom_buffer* buf, Ip_u32 attr_flags, struct Ip_stat* file_attr)
|
|
{
|
|
if(attr_flags & IPSSH_FILEXFER_ATTR_SIZE)
|
|
{
|
|
Ip_u32 len;
|
|
if(ipssh_buffer_get_uint(buf, &len) || /* hi */
|
|
ipssh_buffer_get_uint(buf, &len) ) /* lo */
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_unpack_attr :: failed to unpack size attribute");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
file_attr->st_size = len;
|
|
}
|
|
if(attr_flags & IPSSH_FILEXFER_ATTR_UIDGID)
|
|
{
|
|
Ip_u32 uid;
|
|
Ip_u32 gid;
|
|
|
|
if(ipssh_buffer_get_uint(buf, &uid) ||
|
|
ipssh_buffer_get_uint(buf, &gid) )
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_unpack_attr :: failed to unpack uid/gid attributes");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
}
|
|
if(attr_flags & IPSSH_FILEXFER_ATTR_PERMISSIONS )
|
|
{
|
|
Ip_u32 mode;
|
|
if(ipssh_buffer_get_uint(buf, &mode) )
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_unpack_attr :: failed to unpack perm attribute");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
file_attr->st_mode = ipssh_mode_ssh2ipcom((Ip_mode_t)mode);
|
|
}
|
|
|
|
if(attr_flags & IPSSH_FILEXFER_ATTR_ACMODTIME)
|
|
{
|
|
Ip_s32 atime, mtime;
|
|
if(ipssh_buffer_get_int(buf, &atime) ||
|
|
ipssh_buffer_get_int(buf, &mtime))
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_unpack_attr :: failed to unpack time attributes");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
file_attr->st_atime = ip_ntohl(atime);
|
|
file_attr->st_mtime = ip_ntohl(mtime);
|
|
}
|
|
if(attr_flags & IPSSH_FILEXFER_ATTR_EXTENDED)
|
|
{
|
|
Ip_u32 count;
|
|
char* type;
|
|
char* data;
|
|
if(ipssh_buffer_get_uint(buf, &count))
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_unpack_attr :: failed to unpack ext count");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
while(count)
|
|
{
|
|
type = ipssh_buffer_get_sshstr(buf);
|
|
if (type)
|
|
ipcom_free(type);
|
|
else
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_unpack_attr :: failed to unpack ext data");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
data = ipssh_buffer_get_sshstr(buf);
|
|
if (data)
|
|
ipcom_free(data);
|
|
else
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_unpack_attr :: failed to unpack ext data");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
}
|
|
|
|
}
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_pack_attr
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipssh_pack_attr(Ipcom_buffer* pkt, struct Ip_stat* buf, Ip_u32 flags)
|
|
{
|
|
if(ipcom_buffer_capacity(pkt) < 32)
|
|
return IPCOM_ERR_FAILED;
|
|
|
|
(void)ipssh_buffer_put_int(pkt, flags);
|
|
if(flags & IPSSH_FILEXFER_ATTR_SIZE)
|
|
{
|
|
/* 64 bits */
|
|
(void)ipcom_buffer_put_int(pkt, 0);
|
|
(void)ipcom_buffer_put_int(pkt, ip_htonl(buf->st_size));
|
|
}
|
|
if(flags & IPSSH_FILEXFER_ATTR_UIDGID)
|
|
{
|
|
(void)ipcom_buffer_put_int(pkt, ip_htonl(buf->st_uid));
|
|
(void)ipcom_buffer_put_int(pkt, ip_htonl(buf->st_gid));
|
|
}
|
|
if(flags & IPSSH_FILEXFER_ATTR_PERMISSIONS)
|
|
{
|
|
Ip_mode_t ssh_attr;
|
|
ssh_attr = ipssh_mode_ipcom2ssh(buf->st_mode);
|
|
(void)ipcom_buffer_put_int(pkt, ip_htonl(ssh_attr));
|
|
}
|
|
if(flags & IPSSH_FILEXFER_ATTR_ACMODTIME)
|
|
{
|
|
(void)ipcom_buffer_put_int(pkt, ip_htonl(buf->st_atime));
|
|
(void)ipcom_buffer_put_int(pkt, ip_htonl(buf->st_mtime));
|
|
}
|
|
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_channel_data_sftp_handler
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipssh_channel_data_sftp_handler(Ipssh_channel* channel, Ipcom_buffer* msg)
|
|
{
|
|
Ip_u32 ch_data_len;
|
|
Ip_err rc;
|
|
|
|
/* Peel off channel data length */
|
|
if(ipssh_buffer_get_uint(msg, &ch_data_len))
|
|
return IPCOM_ERR_FAILED;
|
|
|
|
rc = ipssh_sftp_msg_handler(channel, msg);
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_send_fxp_status
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipssh_send_fxp_status(Ipssh_channel* channel,
|
|
Ip_u32 req_id,
|
|
Ip_u32 status)
|
|
{
|
|
Ipcom_buffer* pkt;
|
|
Ip_s32 rc;
|
|
|
|
IPCOM_LOG4(DEBUG, "ipssh_send_fxp_status :: my ch: %d, peer ch: %d, req_id: %d, status: %d",
|
|
channel->my_ch_id, channel->peer_ch_id, req_id, status);
|
|
|
|
pkt = ipssh_buffer_new_sftp_pkt(40, IPSSH_FXP_STATUS);
|
|
if(!pkt)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_send_fxp_status :: out of memory");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
(void)ipcom_buffer_put_int(pkt, ip_htonl(req_id));
|
|
(void)ipcom_buffer_put_int(pkt, ip_htonl(status));
|
|
(void)ipssh_buffer_put_sshstr(pkt, ""); /* Empty error message */
|
|
(void)ipssh_buffer_put_sshstr(pkt, ""); /* Empty lang tag */
|
|
|
|
rc = ipssh_send_fxp_msg(channel, pkt);
|
|
|
|
ipcom_buffer_free(pkt);
|
|
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_send_fxp_version
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipssh_send_fxp_version(Ipssh_channel* channel)
|
|
{
|
|
Ip_err rc;
|
|
Ipcom_buffer* pkt;
|
|
|
|
IPCOM_LOG0(DEBUG, "ipssh_send_fxp_version");
|
|
|
|
pkt = ipssh_buffer_new_sftp_pkt(4, IPSSH_FXP_VERSION);
|
|
|
|
if( !pkt)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_send_fxp_version, failed to allocate packet");
|
|
return IPCOM_ERR_NO_MEMORY;
|
|
}
|
|
|
|
(void)ipssh_buffer_put_int(pkt, 3);
|
|
|
|
rc = ipssh_send_fxp_msg(channel, pkt);
|
|
ipcom_buffer_free(pkt);
|
|
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_send_fxp_name
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipssh_send_fxp_name(Ipssh_channel* channel,
|
|
Ip_u32 req_id,
|
|
char* path)
|
|
{
|
|
Ipcom_buffer* pkt_buf;
|
|
Ip_err rc;
|
|
|
|
IPCOM_LOG2(DEBUG, "ipssh_send_fxp_name :: my_ch_id: %d, req_id: %d", channel->my_ch_id, req_id);
|
|
|
|
pkt_buf = ipssh_buffer_new_sftp_pkt(64 + 2*ipcom_strlen(path), IPSSH_FXP_NAME); /* 21 + strlen path only required */
|
|
if(!pkt_buf)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_send_fxp_name :: out of memory");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto cleanup;
|
|
}
|
|
|
|
if(ipcom_buffer_put_int(pkt_buf, ip_htonl(req_id)) ||
|
|
ipcom_buffer_put_int(pkt_buf, ip_htonl(1)) || /* count */
|
|
ipssh_buffer_put_sshstr(pkt_buf, path) ||
|
|
ipssh_buffer_put_sshstr(pkt_buf, path) || /* Long name without long listing info */
|
|
ipcom_buffer_put_int(pkt_buf, ip_htonl(0)) ) /* attr, no attributes present */
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_send_fxp_name :: failed to pack message");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto cleanup;
|
|
}
|
|
|
|
rc = ipssh_send_fxp_msg(channel, pkt_buf);
|
|
|
|
cleanup:
|
|
if(pkt_buf)
|
|
ipcom_buffer_free(pkt_buf);
|
|
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_send_fxp_handle
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipssh_send_fxp_handle(Ipssh_channel* channel,
|
|
Ip_u32 req_id,
|
|
Ipssh_sftp_ext_handle* handle,
|
|
Ip_u32 handle_len)
|
|
{
|
|
Ipcom_buffer* pkt_buf;
|
|
Ip_s32 rc;
|
|
|
|
IPCOM_LOG3(DEBUG, "ipssh_send_fxp_handle :: my_ch_id: %d, peer_ch_id: %d, req_id: %d",
|
|
channel->my_ch_id, channel->peer_ch_id, req_id);
|
|
|
|
pkt_buf = ipssh_buffer_new_sftp_pkt(64 + handle_len, IPSSH_FXP_HANDLE);
|
|
if(!pkt_buf)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_send_fxp_handle :: out of memory");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
if(ipcom_buffer_put_int(pkt_buf, ip_htonl(req_id)) ||
|
|
ipssh_buffer_put_sshbuf(pkt_buf, (Ip_u8*)handle, handle_len) )
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_send_fxp_handle :: failed to pack message");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto cleanup;
|
|
}
|
|
|
|
rc = ipssh_send_fxp_msg(channel, pkt_buf);
|
|
|
|
cleanup:
|
|
if(pkt_buf)
|
|
ipcom_buffer_free(pkt_buf);
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_msg_fxp_write
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipssh_msg_fxp_write(Ipssh_channel* channel,
|
|
Ipcom_buffer* in_pkt)
|
|
{
|
|
Ipssh_sftp_ext_handle* handle = IP_NULL;
|
|
Ip_s32 rc;
|
|
Ip_u32 handle_len;
|
|
Ipssh_sftp_int_handle* int_handle;
|
|
Ip_u32 req_id;
|
|
Ip_u64 offset;
|
|
Ip_u32 len;
|
|
Ip_s32 bytes_written;
|
|
|
|
/* Unpack message */
|
|
if(ipssh_buffer_get_uint(in_pkt, &req_id) ||
|
|
!(handle = (Ipssh_sftp_ext_handle*)ipssh_buffer_get_sshbuf(in_pkt, &handle_len)) ||
|
|
ipssh_buffer_get_u64(in_pkt, &offset) ||
|
|
ipssh_buffer_get_uint(in_pkt, &len) || ipcom_buffer_len(in_pkt) < len)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_msg_fxp_write :: failed to unpack message");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto cleanup;
|
|
}
|
|
|
|
IPCOM_LOG5(DEBUG, "ipssh_msg_fxp_write :: my_ch_id: %d, peer_ch_id: %d, req_id: %d, offset: %d, len: %d",
|
|
channel->my_ch_id, channel->peer_ch_id, req_id, IP_U64_GETLO(offset), len);
|
|
|
|
if(ipssh_validate_handle(handle, handle_len) )
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_msg_fxp_write :: ipssh_validate_handle() failed");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto cleanup;
|
|
}
|
|
|
|
if(!(int_handle = ipssh_map_lookup(&(channel->data.sftp.handle_map), handle->id)) )
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_msg_fxp_write :: ipssh_map_lookup() failed");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto cleanup;
|
|
}
|
|
if(IP_U64_NEQUAL(offset,int_handle->write_pos))
|
|
{
|
|
ip_assert(int_handle->funcs->lseek_cb);
|
|
if(int_handle->funcs->lseek_cb(int_handle->fd, offset, IP_SEEK_SET) == -1)
|
|
{
|
|
IPCOM_LOG1(ERR, "ipssh_msg_fxp_write :: lseek_cb() failed, %s", ipcom_strerror(ipcom_errno));
|
|
rc = ipssh_send_fxp_status(channel, req_id, IPSSH_FX_FAILURE);
|
|
goto cleanup;
|
|
}
|
|
int_handle->write_pos = offset;
|
|
}
|
|
ip_assert(int_handle->funcs->write_cb);
|
|
bytes_written = (Ip_s32)int_handle->funcs->write_cb(int_handle->fd, (const char*)ipcom_buffer_start_ptr(in_pkt), (Ip_size_t)len); /*lint !e64*/
|
|
if(bytes_written != (Ip_s32)len)
|
|
{
|
|
IPCOM_LOG1(ERR, "ipssh_msg_fxp_write :: write_cb() failed, %s", ipcom_strerror(ipcom_errno));
|
|
rc = ipssh_send_fxp_status(channel, req_id, IPSSH_FX_FAILURE);
|
|
goto cleanup;
|
|
}
|
|
IP_U64_ADD32(int_handle->write_pos,bytes_written);
|
|
|
|
(void)ipcom_buffer_consume(in_pkt, len);
|
|
|
|
rc = ipssh_send_fxp_status(channel, req_id, IPSSH_FX_OK);
|
|
|
|
cleanup:
|
|
if(handle)
|
|
ipcom_free(handle);
|
|
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_msg_fxp_read
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipssh_msg_fxp_read(Ipssh_channel* channel,
|
|
Ipcom_buffer* in_pkt)
|
|
{
|
|
Ipssh_sftp_ext_handle* handle = IP_NULL;
|
|
Ip_s32 rc = IPCOM_SUCCESS;
|
|
Ip_u32 handle_len;
|
|
Ipcom_buffer* out_pkt = IP_NULL;
|
|
Ipssh_sftp_int_handle* int_handle;
|
|
Ip_u32 req_id;
|
|
Ip_u64 offset;
|
|
Ip_u32 len;
|
|
int msg_size;
|
|
Ip_s32 bytes_read;
|
|
Ip_s32 bytes_requested;
|
|
Ip_u32 data_len_pos;
|
|
|
|
/* Unpack message */
|
|
if(ipssh_buffer_get_uint(in_pkt, &req_id) ||
|
|
!(handle = (Ipssh_sftp_ext_handle*)ipssh_buffer_get_sshbuf(in_pkt, &handle_len)) ||
|
|
ipssh_buffer_get_u64(in_pkt, &offset) ||
|
|
ipssh_buffer_get_uint(in_pkt, &len) )
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_msg_fxp_read :: failed to unpack message");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto cleanup;
|
|
}
|
|
|
|
IPCOM_LOG4(DEBUG, "ipssh_msg_fxp_read :: my_ch_id: %d, peer_ch_id: %d, offset: %d, len: %d",
|
|
channel->my_ch_id, channel->peer_ch_id, IP_U64_GETLO(offset), len);
|
|
|
|
if(ipssh_validate_handle(handle, handle_len) )
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_msg_fxp_read :: ipssh_validate_handle() failed");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto cleanup;
|
|
}
|
|
|
|
if(!(int_handle = ipssh_map_lookup(&(channel->data.sftp.handle_map), handle->id)) )
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_msg_fxp_read :: ipssh_map_lookup() failed");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto cleanup;
|
|
}
|
|
|
|
/* Send IPSSH_FXP_DATA message */
|
|
if (channel->ssh_conn->flags & IPSSH_FLAG_BUG_UNRESTRICTED_SFTP_MSG_SIZE)
|
|
msg_size = len+8;
|
|
else
|
|
msg_size = IP_MIN(IPSSH_CH_MAX_PKT-5, len+8);
|
|
|
|
ip_assert(msg_size > 8);
|
|
out_pkt = ipssh_buffer_new_sftp_pkt(msg_size, IPSSH_FXP_DATA);
|
|
if(!out_pkt)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_msg_fxp_read :: out of memory");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto cleanup;
|
|
}
|
|
|
|
|
|
(void)ipssh_buffer_put_int(out_pkt, req_id);
|
|
data_len_pos = (Ip_u32)ipcom_buffer_len(out_pkt);
|
|
(void)ipcom_buffer_decr_cap(out_pkt, 4);
|
|
if(IP_U64_NEQUAL(offset, int_handle->read_pos))
|
|
{
|
|
ip_assert(int_handle->funcs->lseek_cb);
|
|
if(int_handle->funcs->lseek_cb(int_handle->fd, offset, IP_SEEK_SET) == -1)
|
|
{
|
|
if(!int_handle->eof)
|
|
{
|
|
IPCOM_LOG1(ERR, "ipssh_msg_fxp_read :: ipcom_lseek() failed, %d", ipcom_errno);
|
|
rc = ipssh_send_fxp_status(channel, req_id, IPSSH_FX_FAILURE);
|
|
goto cleanup;
|
|
}
|
|
}
|
|
int_handle->read_pos = offset;
|
|
}
|
|
ip_assert(int_handle->funcs->read_cb);
|
|
bytes_requested = (Ip_s32)ipcom_buffer_capacity(out_pkt)-IPSSH_MAX_PAD; /* Reserve space for padding */
|
|
bytes_read = (Ip_s32)int_handle->funcs->read_cb(int_handle->fd,
|
|
(char*)ipcom_buffer_end_ptr(out_pkt),
|
|
bytes_requested);
|
|
if(bytes_read < 0 )
|
|
{
|
|
IPCOM_LOG1(INFO, "ipssh_msg_fxp_read :: read_cb() failed, errno=%d", ipcom_errno);
|
|
rc = ipssh_send_fxp_status(channel, req_id, IPSSH_FX_FAILURE);
|
|
goto cleanup;
|
|
}
|
|
if(bytes_read == 0)
|
|
{
|
|
if(ipssh_send_fxp_status(channel, req_id, IPSSH_FX_EOF) )
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_msg_fxp_read :: ipssh_send_fxp_status() failed");
|
|
rc = IPCOM_ERR_FAILED;
|
|
}
|
|
goto cleanup;
|
|
}
|
|
IP_U64_ADD32(int_handle->read_pos,bytes_read);
|
|
if(bytes_read < bytes_requested)
|
|
int_handle->eof = 1;
|
|
|
|
(void)ipcom_buffer_decr_cap(out_pkt, bytes_read);
|
|
IPSSH_SET_32_PTR(ipcom_buffer_ptr2pos(out_pkt, data_len_pos), bytes_read); /*lint !e666*/
|
|
rc = ipssh_send_fxp_msg(channel, out_pkt);
|
|
|
|
cleanup:
|
|
if(handle)
|
|
ipcom_free(handle);
|
|
if(out_pkt)
|
|
ipcom_buffer_free(out_pkt);
|
|
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_msg_fxp_readdir
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipssh_msg_fxp_readdir(Ipssh_channel* channel,
|
|
Ipcom_buffer* pkt_buf)
|
|
{
|
|
Ip_u32 req_id;
|
|
Ipssh_sftp_ext_handle* handle = IP_NULL;
|
|
Ip_s32 rc = IPCOM_SUCCESS;
|
|
Ip_u32 handle_len, count;
|
|
int count_pos;
|
|
Ipcom_buffer* out_pkt = IP_NULL;
|
|
Ipssh_sftp_int_handle* map_entry;
|
|
char* tmp_buf = IP_NULL;
|
|
|
|
/* Unpack message */
|
|
if(ipssh_buffer_get_uint(pkt_buf, &(req_id)) ||
|
|
!(handle = (Ipssh_sftp_ext_handle*)ipssh_buffer_get_sshbuf(pkt_buf, &handle_len)))
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_msg_fxp_readdir :: failed to unpack message");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto cleanup;
|
|
}
|
|
|
|
IPCOM_LOG2(DEBUG, "ipssh_msg_fxp_readdir :: my_ch_id: %d, peer_ch_id: %d",
|
|
channel->my_ch_id, channel->peer_ch_id);
|
|
|
|
if(ipssh_validate_handle(handle, handle_len) )
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_msg_fxp_readdir :: ipssh_validate_handle() failed");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto cleanup;
|
|
}
|
|
|
|
out_pkt = ipssh_buffer_new_sftp_pkt(IPSSH_SFTP_READDIR_BUF_SIZE, IPSSH_FXP_NAME);
|
|
if(!out_pkt )
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_msg_fxp_readdir :: out of memory");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto cleanup;
|
|
}
|
|
if(!(map_entry = ipssh_map_lookup(&(channel->data.sftp.handle_map), handle->id)) )
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_msg_fxp_readdir :: ipssh_map_lookup() failed");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto cleanup;
|
|
}
|
|
if(map_entry->eof)
|
|
{
|
|
if(ipssh_send_fxp_status(channel, req_id, IPSSH_FX_EOF) )
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_msg_fxp_readdir :: ipssh_send_fxp_status() failed");
|
|
rc = IPCOM_ERR_FAILED;
|
|
}
|
|
goto cleanup;
|
|
}
|
|
|
|
/* Construct FXP_NAME packet */
|
|
(void)ipssh_buffer_put_int(out_pkt, req_id);
|
|
count_pos = (int)ipcom_buffer_len(out_pkt);
|
|
(void)ipcom_buffer_decr_cap(out_pkt, 4);
|
|
count = 0;
|
|
tmp_buf = ipcom_malloc(256);
|
|
if(tmp_buf == IP_NULL)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_msg_fxp_readdir :: out of memory");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto cleanup;
|
|
}
|
|
ip_assert(map_entry->funcs->readdir_cb);
|
|
|
|
while( ipcom_buffer_capacity(out_pkt) > 256 )
|
|
{
|
|
struct Ip_stat file_stat;
|
|
struct Ip_dirent* dir_entry;
|
|
|
|
dir_entry = map_entry->funcs->readdir_cb(map_entry->dir);
|
|
|
|
if(!dir_entry)
|
|
{
|
|
map_entry->eof = 1;
|
|
break;
|
|
}
|
|
count++;
|
|
ipcom_strcpy(tmp_buf, map_entry->path);
|
|
if(tmp_buf[ipcom_strlen(tmp_buf)-1] != '/')
|
|
ipcom_strcat(tmp_buf, "/");
|
|
ipcom_strcat(tmp_buf, dir_entry->d_name);
|
|
if(!map_entry->funcs->stat_cb ||
|
|
map_entry->funcs->stat_cb(tmp_buf, &file_stat) != IPCOM_SUCCESS)
|
|
{
|
|
ipcom_memset(&file_stat, 0, sizeof(file_stat));
|
|
}
|
|
ipssh_make_long_name(map_entry->path, dir_entry->d_name, &file_stat, tmp_buf);
|
|
if(ipssh_buffer_put_sshstr(out_pkt, dir_entry->d_name) ||
|
|
ipssh_buffer_put_sshstr(out_pkt, tmp_buf) ||
|
|
ipssh_pack_stat_data(out_pkt, &file_stat))
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_msg_fxp_readdir :: failed to pack FXP_NAME packet");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto cleanup;
|
|
}
|
|
}
|
|
IPSSH_SET_32_PTR(ipcom_buffer_ptr2pos(out_pkt, count_pos), count); /*lint !e666*/
|
|
|
|
rc = ipssh_send_fxp_msg(channel, out_pkt);
|
|
|
|
cleanup:
|
|
if(handle)
|
|
ipcom_free(handle);
|
|
if(out_pkt)
|
|
ipcom_buffer_free(out_pkt);
|
|
if(tmp_buf)
|
|
ipcom_free(tmp_buf);
|
|
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_msg_fxp_close
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipssh_msg_fxp_close(Ipssh_channel* channel,
|
|
Ipcom_buffer* pkt_buf)
|
|
{
|
|
Ipssh_sftp_ext_handle* handle = IP_NULL;
|
|
Ip_u32 req_id, handle_len;
|
|
Ip_s32 rc;
|
|
|
|
/* Unpack message */
|
|
if(ipssh_buffer_get_uint(pkt_buf, &(req_id)) ||
|
|
!(handle = (Ipssh_sftp_ext_handle*)ipssh_buffer_get_sshbuf(pkt_buf, &handle_len)))
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_msg_fxp_close :: failed to unpack message");
|
|
(void)ipssh_send_fxp_status(channel, req_id, IPSSH_FX_FAILURE);
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto cleanup;
|
|
}
|
|
|
|
IPCOM_LOG1(DEBUG, "ipssh_msg_fxp_close, req_id: %d", req_id);
|
|
|
|
if(ipssh_validate_handle(handle, handle_len) )
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_msg_fxp_close :: ipssh_validate_handle() failed");
|
|
(void)ipssh_send_fxp_status(channel, req_id, IPSSH_FX_FAILURE);
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto cleanup;
|
|
}
|
|
if(ipssh_map_remove(&(channel->data.sftp.handle_map), handle->id) == IPCOM_SUCCESS)
|
|
{
|
|
rc = ipssh_send_fxp_status(channel, req_id, IPSSH_FX_OK);
|
|
}
|
|
else
|
|
{
|
|
(void)ipssh_send_fxp_status(channel, req_id, IPSSH_FX_FAILURE);
|
|
rc = IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
cleanup:
|
|
if(handle)
|
|
ipcom_free(handle);
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_msg_fxp_lstat
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipssh_msg_fxp_lstat(Ipssh_channel* channel,
|
|
Ipcom_buffer* pkt_buf)
|
|
{
|
|
char* path = IP_NULL;
|
|
Ip_u32 req_id;
|
|
Ip_s32 rc = IPCOM_ERR_FAILED;
|
|
Ipcom_buffer* out_pkt = IP_NULL;
|
|
struct Ip_stat buf;
|
|
Ipssh_sftp_func_cb* funcs;
|
|
char* int_path = IP_NULL;
|
|
|
|
/* Unpack message */
|
|
if(ipssh_buffer_get_uint(pkt_buf, &req_id) ||
|
|
!(path=ipssh_buffer_get_sshstr(pkt_buf)) )
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_msg_fxp_lstat :: failed to unpack message");
|
|
goto cleanup;
|
|
}
|
|
|
|
if (ipssh_make_ext_int_paths(path, channel->ssh_conn->config.sftp_start_dir, channel->ssh_conn->sh_ctx, IP_NULL, &int_path) != IPCOM_SUCCESS)
|
|
{
|
|
IPCOM_LOG0(DEBUG, "ipssh_msg_fxp_lstat :: ipssh_make_ext_int_paths failed");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto cleanup;
|
|
}
|
|
|
|
IPCOM_LOG4(DEBUG, "ipssh_msg_fxp_lstat :: my_ch_id: %d, srv ch id: %d, req_id: %d, path=%s",
|
|
channel->my_ch_id, channel->peer_ch_id, req_id, path);
|
|
|
|
funcs = ipssh_get_sftp_func_cb(int_path);
|
|
if(!funcs || !funcs->stat_cb)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_msg_fxp_lstat :: no stat callback");
|
|
rc = ipssh_send_fxp_status(channel, req_id, IPSSH_FX_FAILURE);
|
|
goto cleanup;
|
|
}
|
|
if(funcs->stat_cb(int_path, &buf))
|
|
{
|
|
IPCOM_LOG1(ERR, "ipssh_msg_fxp_lstat :: stat_cb() failed, %s", ipcom_strerror(ipcom_errno));
|
|
rc = ipssh_send_fxp_status(channel, req_id, IPSSH_FX_NO_SUCH_FILE);
|
|
goto cleanup;
|
|
}
|
|
|
|
out_pkt = ipssh_buffer_new_sftp_pkt(128, IPSSH_FXP_ATTRS);
|
|
if(!out_pkt)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_msg_fxp_lstat :: out of memory");
|
|
goto cleanup;
|
|
}
|
|
|
|
(void)ipcom_buffer_put_int(out_pkt, ip_htonl(req_id));
|
|
(void)ipssh_pack_stat_data(out_pkt, &buf);
|
|
|
|
rc = ipssh_send_fxp_msg(channel, out_pkt);
|
|
|
|
cleanup:
|
|
if(path)
|
|
ipcom_free(path);
|
|
if(int_path)
|
|
ipcom_free(int_path);
|
|
if(out_pkt)
|
|
ipcom_buffer_free(out_pkt);
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_msg_fxp_setstat
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipssh_msg_fxp_setstat(Ipssh_channel* channel,
|
|
Ipcom_buffer* pkt_buf)
|
|
{
|
|
char* path = IP_NULL;
|
|
Ip_u32 req_id;
|
|
Ip_u32 attr_flags;
|
|
Ip_s32 rc = IPCOM_ERR_FAILED;
|
|
struct Ip_stat file_attr;
|
|
|
|
/* Unpack message */
|
|
if(ipssh_buffer_get_uint(pkt_buf, &req_id) ||
|
|
!(path=ipssh_buffer_get_sshstr(pkt_buf)) ||
|
|
ipssh_buffer_get_uint(pkt_buf, &attr_flags) ||
|
|
ipssh_unpack_attr(pkt_buf, attr_flags, &file_attr))
|
|
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_msg_fxp_setstat :: failed to unpack message");
|
|
goto cleanup;
|
|
}
|
|
|
|
IPCOM_LOG4(DEBUG, "ipssh_msg_fxp_setstat :: my_ch_id: %d, srv ch id: %d, req_id: %d, path=%s",
|
|
channel->my_ch_id, channel->peer_ch_id, req_id, path);
|
|
IPCOM_LOG0(INFO, "Received FXP_SETSTAT, ignoring");
|
|
|
|
rc = ipssh_send_fxp_status(channel, req_id, IPSSH_FX_OK);
|
|
|
|
cleanup:
|
|
if(path)
|
|
ipcom_free(path);
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_msg_fxp_rename
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipssh_msg_fxp_rename(Ipssh_channel* channel,
|
|
Ipcom_buffer* pkt_buf)
|
|
{
|
|
Ip_u32 req_id;
|
|
Ip_s32 rc = IPCOM_ERR_FAILED;
|
|
char* oldpath = IP_NULL;
|
|
char* newpath = IP_NULL;
|
|
char* int_oldpath = IP_NULL;
|
|
char* int_newpath = IP_NULL;
|
|
Ipssh_sftp_func_cb* funcs;
|
|
|
|
/* Unpack message */
|
|
if(ipssh_buffer_get_uint(pkt_buf, &req_id) ||
|
|
!(oldpath=ipssh_buffer_get_sshstr(pkt_buf)) ||
|
|
!(newpath=ipssh_buffer_get_sshstr(pkt_buf)) )
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_msg_fxp_rename :: failed to unpack message");
|
|
goto cleanup;
|
|
}
|
|
IPCOM_LOG5(DEBUG, "ipssh_msg_fxp_rename :: my_ch_id: %d, peer_ch_id: %d, req_id:%d, oldpath=%s, newpath=%s",
|
|
channel->my_ch_id, channel->peer_ch_id, req_id, oldpath, newpath);
|
|
|
|
if (ipssh_make_ext_int_paths(oldpath, channel->ssh_conn->config.sftp_start_dir,
|
|
channel->ssh_conn->sh_ctx, IP_NULL, &int_oldpath) != IPCOM_SUCCESS ||
|
|
ipssh_make_ext_int_paths(newpath, channel->ssh_conn->config.sftp_start_dir,
|
|
channel->ssh_conn->sh_ctx, IP_NULL, &int_newpath) != IPCOM_SUCCESS)
|
|
{
|
|
IPCOM_LOG0(DEBUG, "ipssh_msg_fxp_rename :: ipssh_make_ext_int_paths failed");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto cleanup;
|
|
}
|
|
|
|
if(ipssh_sftp_check_access_cb(channel->ssh_conn->user, IPSSH_FXP_REMOVE, int_oldpath, 0) != IPCOM_SUCCESS)
|
|
{
|
|
rc = ipssh_send_fxp_status(channel, req_id, IPSSH_FX_PERMISSION_DENIED);
|
|
goto cleanup;
|
|
}
|
|
|
|
if(ipssh_sftp_check_access_cb(channel->ssh_conn->user, IPSSH_FXP_OPEN, int_newpath, IPSSH_FXP_WRITE) != IPCOM_SUCCESS)
|
|
{
|
|
rc = ipssh_send_fxp_status(channel, req_id, IPSSH_FX_PERMISSION_DENIED);
|
|
goto cleanup;
|
|
}
|
|
|
|
funcs = ipssh_get_sftp_func_cb(int_oldpath);
|
|
if(!funcs || !funcs->rename_cb)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_msg_fxp_rename :: no rename callback");
|
|
rc = ipssh_send_fxp_status(channel, req_id, IPSSH_FX_FAILURE);
|
|
goto cleanup;
|
|
}
|
|
if(funcs->rename_cb(int_oldpath, int_newpath))
|
|
{
|
|
IPCOM_LOG3(ERR, "ipssh_msg_fxp_rename :: rename callback failed, oldpath: %s, newpath: %s, errno: %d",
|
|
int_oldpath, int_newpath, ipcom_errno);
|
|
rc = ipssh_send_fxp_status(channel, req_id, IPSSH_FX_FAILURE);
|
|
goto cleanup;
|
|
}
|
|
else
|
|
rc = ipssh_send_fxp_status(channel, req_id, IPSSH_FX_OK);
|
|
|
|
cleanup:
|
|
if(newpath)
|
|
ipcom_free(newpath);
|
|
if(oldpath)
|
|
ipcom_free(oldpath);
|
|
if(int_newpath)
|
|
ipcom_free(int_newpath);
|
|
if(int_oldpath)
|
|
ipcom_free(int_oldpath);
|
|
|
|
return rc;
|
|
|
|
}
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_msg_fxp_rmdir
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipssh_msg_fxp_rmdir(Ipssh_channel* channel,
|
|
Ipcom_buffer* pkt_buf)
|
|
{
|
|
Ip_u32 req_id;
|
|
Ip_s32 rc = IPCOM_ERR_FAILED;
|
|
char* path = IP_NULL;
|
|
Ipssh_sftp_func_cb* funcs;
|
|
char* int_path = IP_NULL;
|
|
|
|
/* Unpack message */
|
|
if(ipssh_buffer_get_uint(pkt_buf, &req_id) || !(path=ipssh_buffer_get_sshstr(pkt_buf)) )
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_msg_fxp_rmdir :: failed to unpack message");
|
|
goto cleanup;
|
|
}
|
|
IPCOM_LOG4(DEBUG, "ipssh_msg_fxp_rmdir :: my_ch_id: %d, peer_ch_id: %d, req_id:%d, path=%s",
|
|
channel->my_ch_id, channel->peer_ch_id, req_id, path);
|
|
|
|
if (ipssh_make_ext_int_paths(path, channel->ssh_conn->config.sftp_start_dir, channel->ssh_conn->sh_ctx, IP_NULL, &int_path) != IPCOM_SUCCESS)
|
|
{
|
|
IPCOM_LOG0(DEBUG, "ipssh_msg_fxp_rmdir :: ipssh_make_ext_int_paths failed");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto cleanup;
|
|
}
|
|
|
|
if(ipssh_sftp_check_access_cb(channel->ssh_conn->user, IPSSH_FXP_RMDIR, int_path, 0) != IPCOM_SUCCESS)
|
|
{
|
|
rc = ipssh_send_fxp_status(channel, req_id, IPSSH_FX_PERMISSION_DENIED);
|
|
goto cleanup;
|
|
}
|
|
funcs = ipssh_get_sftp_func_cb(int_path);
|
|
if(!funcs || !funcs->rmdir_cb)
|
|
{
|
|
IPCOM_LOG1(ERR, "ipssh_msg_fxp_rmdir :: failed to get rmdir callback for file %s", int_path);
|
|
rc = ipssh_send_fxp_status(channel, req_id, IPSSH_FX_FAILURE);
|
|
goto cleanup;
|
|
}
|
|
if(funcs->rmdir_cb(int_path) != 0 )
|
|
{
|
|
IPCOM_LOG2(ERR, "ipssh_msg_fxp_rmdir :: rmdir callback() failed for %s, errno: %d",
|
|
path, ipcom_errno);
|
|
rc = ipssh_send_fxp_status(channel, req_id, IPSSH_FX_FAILURE);
|
|
}
|
|
else
|
|
rc = ipssh_send_fxp_status(channel, req_id, IPSSH_FX_OK);
|
|
|
|
cleanup:
|
|
if(path)
|
|
ipcom_free(path);
|
|
if(int_path)
|
|
ipcom_free(int_path);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_msg_fxp_mkdir
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipssh_msg_fxp_mkdir(Ipssh_channel* channel,
|
|
Ipcom_buffer* pkt_buf)
|
|
{
|
|
Ip_u32 req_id;
|
|
Ip_s32 rc = IPCOM_ERR_FAILED;
|
|
char* path = IP_NULL;
|
|
Ip_u32 attr_flags;
|
|
struct Ip_stat dir_attr;
|
|
Ipssh_sftp_func_cb* funcs;
|
|
char* int_path = IP_NULL;
|
|
|
|
/* Resonable default value in case message does not contain file attributes */
|
|
dir_attr.st_mode = 0777;
|
|
|
|
/* Unpack message */
|
|
if(ipssh_buffer_get_uint(pkt_buf, &req_id) ||
|
|
!(path=ipssh_buffer_get_sshstr(pkt_buf)) )
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_msg_fxp_mkdir :: failed to unpack message");
|
|
goto cleanup;
|
|
}
|
|
if(ipcom_buffer_len(pkt_buf) >= 4)
|
|
{
|
|
if(ipssh_buffer_get_uint(pkt_buf, &attr_flags) || ipssh_unpack_attr(pkt_buf, attr_flags, &dir_attr))
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_msg_fxp_mkdir :: failed to unpack file attributes");
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
if (ipssh_make_ext_int_paths(path, channel->ssh_conn->config.sftp_start_dir, channel->ssh_conn->sh_ctx, IP_NULL, &int_path) != IPCOM_SUCCESS)
|
|
{
|
|
IPCOM_LOG0(DEBUG, "ipssh_msg_fxp_mkdir :: ipssh_make_ext_int_paths failed");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto cleanup;
|
|
}
|
|
|
|
IPCOM_LOG4(DEBUG, "ipssh_msg_fxp_mkdir :: my_ch_id: %d, peer_ch_id: %d, req_id:%d, path=%s",
|
|
channel->my_ch_id, channel->peer_ch_id, req_id, int_path);
|
|
|
|
if(ipssh_sftp_check_access_cb(channel->ssh_conn->user, IPSSH_FXP_MKDIR, int_path, 0) != IPCOM_SUCCESS)
|
|
{
|
|
rc = ipssh_send_fxp_status(channel, req_id, IPSSH_FX_PERMISSION_DENIED);
|
|
goto cleanup;
|
|
}
|
|
funcs = ipssh_get_sftp_func_cb(int_path);
|
|
if(!funcs || !funcs->mkdir_cb)
|
|
{
|
|
IPCOM_LOG1(ERR, "ipssh_msg_fxp_mkdir :: failed to get mkdir callback for file %s", int_path);
|
|
rc = ipssh_send_fxp_status(channel, req_id, IPSSH_FX_FAILURE);
|
|
goto cleanup;
|
|
}
|
|
if(funcs->mkdir_cb(int_path, dir_attr.st_mode) != 0 )
|
|
{
|
|
IPCOM_LOG2(ERR, "ipssh_msg_fxp_mkdir :: ipcom_mkdir() failed for %s, errno: %d",
|
|
int_path, ipcom_errno);
|
|
rc = ipssh_send_fxp_status(channel, req_id, IPSSH_FX_FAILURE);
|
|
}
|
|
else
|
|
rc = ipssh_send_fxp_status(channel, req_id, IPSSH_FX_OK);
|
|
|
|
cleanup:
|
|
if(path)
|
|
ipcom_free(path);
|
|
if(int_path)
|
|
ipcom_free(int_path);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_msg_fxp_remove
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipssh_msg_fxp_remove(Ipssh_channel* channel,
|
|
Ipcom_buffer* pkt_buf)
|
|
{
|
|
Ip_u32 req_id;
|
|
Ip_s32 rc = IPCOM_ERR_FAILED;
|
|
char* path = IP_NULL;
|
|
char* int_path = IP_NULL;
|
|
Ipssh_sftp_func_cb* funcs;
|
|
|
|
/* Unpack message */
|
|
if(ipssh_buffer_get_uint(pkt_buf, &req_id) ||
|
|
!(path=ipssh_buffer_get_sshstr(pkt_buf)) )
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_msg_fxp_remove :: failed to unpack message");
|
|
goto cleanup;
|
|
}
|
|
|
|
if (ipssh_make_ext_int_paths(path, channel->ssh_conn->config.sftp_start_dir, channel->ssh_conn->sh_ctx, IP_NULL, &int_path) != IPCOM_SUCCESS)
|
|
{
|
|
IPCOM_LOG0(DEBUG, "ipssh_msg_fxp_remove :: ipssh_make_ext_int_paths failed");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto cleanup;
|
|
}
|
|
|
|
IPCOM_LOG4(DEBUG, "ipssh_msg_fxp_remove :: my_ch_id: %d, peer_ch_id: %d, req_id:%d, path=%s",
|
|
channel->my_ch_id, channel->peer_ch_id, req_id, int_path);
|
|
|
|
if(ipssh_sftp_check_access_cb(channel->ssh_conn->user, IPSSH_FXP_REMOVE, int_path, 0) != IPCOM_SUCCESS)
|
|
{
|
|
rc = ipssh_send_fxp_status(channel, req_id, IPSSH_FX_PERMISSION_DENIED);
|
|
goto cleanup;
|
|
}
|
|
funcs = ipssh_get_sftp_func_cb(int_path);
|
|
if(!funcs || !funcs->unlink_cb)
|
|
{
|
|
IPCOM_LOG1(ERR, "ipssh_msg_fxp_remove :: no unlink callback: %s", int_path);
|
|
rc = ipssh_send_fxp_status(channel, req_id, IPSSH_FX_FAILURE);
|
|
goto cleanup;
|
|
}
|
|
|
|
if(funcs->unlink_cb(int_path) != 0 )
|
|
{
|
|
IPCOM_LOG2(ERR, "ipssh_msg_fxp_remove :: ipcom_unlink() failed for %s, errno: %d",
|
|
int_path, ipcom_errno);
|
|
rc = ipssh_send_fxp_status(channel, req_id, IPSSH_FX_FAILURE);
|
|
}
|
|
else
|
|
rc = ipssh_send_fxp_status(channel, req_id, IPSSH_FX_OK);
|
|
|
|
cleanup:
|
|
if(path)
|
|
ipcom_free(path);
|
|
if(int_path)
|
|
ipcom_free(int_path);
|
|
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_msg_fxp_open
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipssh_msg_fxp_open(Ipssh_channel* channel,
|
|
Ipcom_buffer* pkt_buf)
|
|
{
|
|
Ip_u32 req_id;
|
|
Ip_u32 flags;
|
|
Ip_u32 attr_flags = 0;
|
|
Ip_u32 x_handle_len;
|
|
Ipssh_sftp_int_handle* handle;
|
|
Ipssh_sftp_ext_handle* x_handle = IP_NULL;
|
|
struct Ip_stat file_stat;
|
|
char* path = IP_NULL;
|
|
Ip_s32 rc = IPCOM_ERR_FAILED;
|
|
|
|
ipcom_memset(&file_stat, 0, sizeof(struct Ip_stat));
|
|
file_stat.st_mode = 0644; /* Set a reasonable default value (-rw-r--r--), in case client sends no file privs */
|
|
|
|
if(!(handle = ipcom_malloc(sizeof(Ipssh_sftp_int_handle))) )
|
|
{
|
|
IPCOM_LOG0(ERR,"ipssh_msg_fxp_open :: out of memory");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
ipcom_memset(handle, 0, sizeof(Ipssh_sftp_int_handle));
|
|
handle->fd = -1;
|
|
handle->type = IPSSH_FILE_HANDLE;
|
|
|
|
/* Unpack message */
|
|
if(ipssh_buffer_get_uint(pkt_buf, &req_id) ||
|
|
!(path=ipssh_buffer_get_sshstr(pkt_buf)) ||
|
|
ipssh_buffer_get_uint(pkt_buf, &flags) ||
|
|
ipssh_buffer_get_uint(pkt_buf, &attr_flags) )
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_msg_fxp_open :: failed to unpack message");
|
|
goto cleanup;
|
|
}
|
|
|
|
if (ipssh_make_ext_int_paths(path, channel->ssh_conn->config.sftp_start_dir, channel->ssh_conn->sh_ctx, IP_NULL, &handle->path) != IPCOM_SUCCESS)
|
|
{
|
|
IPCOM_LOG0(DEBUG, "ipssh_msg_fxp_open :: ipssh_make_ext_int_paths failed");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto cleanup;
|
|
}
|
|
|
|
IPCOM_LOG5(DEBUG, "ipssh_msg_fxp_open :: my_ch_id: %d, peer_ch_id: %d, req_id:%d, path=%s, flags: %d",
|
|
channel->my_ch_id, channel->peer_ch_id, req_id, handle->path, flags); /*lint !e644*/
|
|
|
|
/* Unpack attr according to attr_flag */
|
|
if(attr_flags != 0 )
|
|
{
|
|
if(ipssh_unpack_attr(pkt_buf, attr_flags, &file_stat) )
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_msg_fxp_open :: failed to unpack attrs");
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
if(ipssh_sftp_check_access_cb(channel->ssh_conn->user, IPSSH_FXP_OPEN, handle->path, flags) != IPCOM_SUCCESS) /*lint !e644*/
|
|
{
|
|
rc = ipssh_send_fxp_status(channel, req_id, IPSSH_FX_PERMISSION_DENIED);
|
|
goto cleanup;
|
|
}
|
|
|
|
if(ipssh_create_handle(&(x_handle), &(x_handle_len)) )
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_msg_fxp_open :: ipssh_create_handle failed");
|
|
goto cleanup;
|
|
}
|
|
handle->id = x_handle->id;
|
|
|
|
/* Set up function pointers */
|
|
handle->funcs = ipssh_get_sftp_func_cb(handle->path);
|
|
if(!handle->funcs || !handle->funcs->open_cb || !handle->funcs->close_cb || !handle->funcs->stat_cb
|
|
|| !handle->funcs->read_cb || !handle->funcs->write_cb || !handle->funcs->lseek_cb
|
|
|| !handle->funcs->opendir_cb || !handle->funcs->closedir_cb || !handle->funcs->readdir_cb
|
|
|| !handle->funcs->mkdir_cb || !handle->funcs->rmdir_cb || !handle->funcs->unlink_cb || !handle->funcs->rename_cb)
|
|
{
|
|
IPCOM_LOG1(ERR, "ipssh_msg_fxp_open :: failed to get callbacks for file: %s", handle->path);
|
|
rc = ipssh_send_fxp_status(channel, req_id, IPSSH_FX_FAILURE);
|
|
goto cleanup;
|
|
}
|
|
handle->fd = handle->funcs->open_cb(handle->path, ipssh_conv_flags(flags), file_stat.st_mode);
|
|
if(handle->fd == -1)
|
|
{
|
|
IPCOM_LOG2(ERR, "ipssh_msg_fxp_open :: open() failed for file: %s, %s",
|
|
handle->path, ipcom_strerror(ipcom_errno));
|
|
rc = ipssh_send_fxp_status(channel, req_id, IPSSH_FX_FAILURE);
|
|
goto cleanup;
|
|
}
|
|
if(ipssh_map_insert(&(channel->data.sftp.handle_map), handle))
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_msg_fxp_open :: ipssh_map_insert failed");
|
|
goto cleanup;
|
|
}
|
|
handle = IP_NULL;
|
|
|
|
if(ipssh_send_fxp_handle(channel, req_id, x_handle, x_handle_len) )
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_msg_fxp_open :: ipssh_send_fxp_handle() failed");
|
|
goto cleanup;
|
|
}
|
|
|
|
rc = IPCOM_SUCCESS;
|
|
|
|
cleanup:
|
|
if (path)
|
|
ipcom_free(path);
|
|
if(handle)
|
|
{
|
|
if(handle->path)
|
|
ipcom_free(handle->path);
|
|
if(handle->fd != -1)
|
|
{
|
|
ip_assert(handle->funcs->close_cb);
|
|
handle->funcs->close_cb(handle->fd); /*lint !e522*/
|
|
}
|
|
ipcom_free(handle);
|
|
}
|
|
if(x_handle)
|
|
ipcom_free(x_handle);
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_msg_fxp_opendir
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipssh_msg_fxp_opendir(Ipssh_channel* channel,
|
|
Ipcom_buffer* pkt_buf)
|
|
{
|
|
Ipssh_sftp_int_handle* entry;
|
|
Ipssh_sftp_ext_handle* handle = IP_NULL;
|
|
Ip_u32 handle_len = 0;
|
|
Ip_s32 rc = IPCOM_SUCCESS;
|
|
Ip_u32 req_id;
|
|
char* path = IP_NULL;
|
|
|
|
IPCOM_LOG0(DEBUG, "ipssh_msg_fxp_opendir");
|
|
|
|
if(!(entry = ipcom_malloc(sizeof(Ipssh_sftp_int_handle))) )
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_msg_fxp_opendir :: out of memory");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
ipcom_memset(entry, 0, sizeof(Ipssh_sftp_int_handle));
|
|
|
|
/* Unpack message */
|
|
if(ipssh_buffer_get_uint(pkt_buf, &(req_id)) ||
|
|
!(path = ipssh_buffer_get_sshstr(pkt_buf)) )
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_msg_fxp_opendir :: failed to unpack message");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto cleanup;
|
|
}
|
|
|
|
if (ipssh_make_ext_int_paths(path, channel->ssh_conn->config.sftp_start_dir, channel->ssh_conn->sh_ctx, IP_NULL, &entry->path) != IPCOM_SUCCESS)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_msg_fxp_opendir :: ipssh_make_ext_int_paths failed");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto cleanup;
|
|
}
|
|
|
|
if(ipssh_sftp_check_access_cb(channel->ssh_conn->user, IPSSH_FXP_OPENDIR, entry->path, 0) != IPCOM_SUCCESS)
|
|
{
|
|
rc = ipssh_send_fxp_status(channel, req_id, IPSSH_FX_PERMISSION_DENIED);
|
|
goto cleanup;
|
|
}
|
|
|
|
entry->funcs = ipssh_get_sftp_func_cb(entry->path);
|
|
if(!entry->funcs || !entry->funcs->open_cb || !entry->funcs->close_cb || !entry->funcs->stat_cb
|
|
|| !entry->funcs->read_cb || !entry->funcs->write_cb || !entry->funcs->lseek_cb
|
|
|| !entry->funcs->opendir_cb || !entry->funcs->closedir_cb || !entry->funcs->readdir_cb
|
|
|| !entry->funcs->mkdir_cb || !entry->funcs->rmdir_cb || !entry->funcs->unlink_cb || !entry->funcs->rename_cb)
|
|
{
|
|
IPCOM_LOG1(ERR, "ipssh_msg_fxp_opendir :: failed to get callbacks for %s", entry->path);
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto cleanup;
|
|
}
|
|
if(!(entry->dir = entry->funcs->opendir_cb(entry->path)))
|
|
{
|
|
rc = ipssh_send_fxp_status(channel, req_id, IPSSH_FX_NO_SUCH_FILE);
|
|
goto cleanup;
|
|
}
|
|
entry->type = IPSSH_DIR_HANDLE;
|
|
|
|
if(ipssh_create_handle(&(handle), &(handle_len)) )
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_msg_fxp_opendir :: ipssh_create_handle failed");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto cleanup;
|
|
}
|
|
entry->id = handle->id;
|
|
|
|
if(ipssh_map_insert(&(channel->data.sftp.handle_map), entry))
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_msg_fxp_opendir :: ipssh_map_insert failed");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto cleanup;
|
|
}
|
|
entry = IP_NULL;
|
|
|
|
if(ipssh_send_fxp_handle(channel, req_id, handle, handle_len) )
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_msg_fxp_opendir :: ipssh_send_fxp_handle() failed");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto cleanup;
|
|
}
|
|
|
|
cleanup:
|
|
if (path)
|
|
ipcom_free(path);
|
|
if (entry)
|
|
{
|
|
if (entry->path)
|
|
ipcom_free(entry->path);
|
|
ipcom_free(entry);
|
|
}
|
|
if (handle)
|
|
ipcom_free(handle);
|
|
return rc;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_msg_fxp_realpath
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipssh_msg_fxp_realpath(Ipssh_channel* channel,
|
|
Ipcom_buffer* pkt_buf)
|
|
{
|
|
Ip_u32 req_id;
|
|
char * path = IP_NULL;
|
|
struct Ip_stat buf;
|
|
Ipssh_sftp_func_cb* funcs;
|
|
Ip_s32 rc = IPCOM_SUCCESS;
|
|
char* int_path = IP_NULL;
|
|
char* ext_path = IP_NULL;
|
|
|
|
/* Unpack message */
|
|
if(ipssh_buffer_get_uint(pkt_buf, &req_id) ||
|
|
!(path = ipssh_buffer_get_sshstr(pkt_buf)) )
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_msg_fxp_realpath :: failed to unpack message");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto cleanup;
|
|
}
|
|
|
|
IPCOM_LOG3(DEBUG, "ipssh_msg_fxp_realpath :: my_ch_id: %d, req_id:%d, path: %s",
|
|
channel->my_ch_id, req_id, path);
|
|
|
|
if (ipssh_make_ext_int_paths(path, channel->ssh_conn->config.sftp_start_dir, channel->ssh_conn->sh_ctx, &ext_path, &int_path) != IPCOM_SUCCESS)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_msg_fxp_realpath :: ipssh_make_ext_int_paths failed");
|
|
rc = ipssh_send_fxp_status(channel, req_id, IPSSH_FX_NO_SUCH_PATH);
|
|
goto cleanup;
|
|
}
|
|
|
|
/* Provide the absolute path in case custom routine requires it */
|
|
funcs = ipssh_get_sftp_func_cb(int_path);
|
|
if(!funcs)
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_msg_fxp_realpath :: no stat callback");
|
|
rc = ipssh_send_fxp_status(channel, req_id, IPSSH_FX_FAILURE);
|
|
goto cleanup;
|
|
}
|
|
|
|
if(funcs->stat_cb(int_path, &buf))
|
|
{
|
|
IPCOM_LOG1(DEBUG, "ipssh_msg_fxp_realpath :: stat_cb() failed, %s", ipcom_strerror(ipcom_errno));
|
|
rc = ipssh_send_fxp_status(channel, req_id, IPSSH_FX_NO_SUCH_FILE);
|
|
goto cleanup;
|
|
}
|
|
|
|
if(ipssh_send_fxp_name(channel, req_id, ext_path) )
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_msg_fxp_realpath :: ipssh_send_fxp_name() failed");
|
|
rc = IPCOM_ERR_FAILED;
|
|
goto cleanup;
|
|
}
|
|
cleanup:
|
|
if(path)
|
|
ipcom_free(path);
|
|
if(int_path)
|
|
ipcom_free(int_path);
|
|
if(ext_path)
|
|
ipcom_free(ext_path);
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_msg_fxp_init
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL Ip_err
|
|
ipssh_msg_fxp_init(Ipssh_channel* channel,
|
|
Ipcom_buffer* pkt_buf)
|
|
{
|
|
Ip_u32 version;
|
|
|
|
IPCOM_LOG1(DEBUG, "ipssh_msg_fxp_init :: my_ch_id:%d", channel->my_ch_id);
|
|
|
|
if(ipssh_buffer_get_uint(pkt_buf, &version) )
|
|
{
|
|
IPCOM_LOG0(ERR, "ipssh_msg_fxp_init :: ipssh_buffer_get_uint() failed");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
|
|
IPCOM_LOG2(DEBUG, "ipssh_msg_fxp_init :: my_ch_id:%d, version: %d", channel->my_ch_id, version);
|
|
|
|
return ipssh_send_fxp_version(channel);
|
|
}
|
|
|
|
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_sftp_cleanup
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipssh_sftp_cleanup(Ipssh_channel* channel)
|
|
{
|
|
Ipssh_sftp_int_handle* handle;
|
|
|
|
if(channel->data.sftp.msg)
|
|
ipcom_buffer_free(channel->data.sftp.msg);
|
|
|
|
for(handle = (Ipssh_sftp_int_handle*)ipcom_list_first(&channel->data.sftp.handle_map);
|
|
handle;
|
|
handle = (Ipssh_sftp_int_handle*)ipcom_list_first(&channel->data.sftp.handle_map))
|
|
{
|
|
ipcom_list_remove(&handle->list);
|
|
|
|
/* check whether a file or directory was opened */
|
|
if (handle->type == IPSSH_DIR_HANDLE)
|
|
{
|
|
if (handle->funcs->closedir_cb)
|
|
handle->funcs->closedir_cb(handle->dir);
|
|
else
|
|
IP_PANIC();
|
|
}
|
|
else if (handle->type == IPSSH_FILE_HANDLE)
|
|
{
|
|
if (handle->funcs->close_cb)
|
|
handle->funcs->close_cb(handle->fd);
|
|
else
|
|
IP_PANIC();
|
|
}
|
|
else
|
|
IP_PANIC();
|
|
|
|
if(handle->path)
|
|
ipcom_free (handle->path);
|
|
|
|
ipcom_free(handle);
|
|
}
|
|
}
|
|
|
|
#ifdef IPSSH_USE_SFTP
|
|
/*
|
|
*===========================================================================
|
|
* ipssh_channel_sftp_init
|
|
*===========================================================================
|
|
* Description:
|
|
* Parameters:
|
|
* Returns:
|
|
*
|
|
*/
|
|
IP_GLOBAL void
|
|
ipssh_channel_sftp_init(Ipssh_channel* channel, int ch_type)
|
|
{
|
|
channel->type = ch_type;
|
|
channel->handler = ipssh_channel_data_sftp_handler;
|
|
ipcom_list_init(&channel->data.sftp.handle_map);
|
|
}
|
|
#endif
|
|
|
|
IP_GLOBAL Ip_err
|
|
ipssh_sftp_subsystem_init_cb(Ipssh_channel* channel, Ip_fd* sock)
|
|
{
|
|
*sock = IP_INVALID_SOCKET;
|
|
if(!channel->ssh_conn->config.sftp)
|
|
{
|
|
IPCOM_LOG0(INFO, "channel request :: sftp session requested, but sftp service not active");
|
|
return IPCOM_ERR_FAILED;
|
|
}
|
|
ipssh_channel_sftp_init(channel, IPSSH_CH_TYPE_SFTP_SRV);
|
|
channel->ssh_conn->conn_state = IPSSH_CONN_STATE_SRV_SSH_SFTP;
|
|
|
|
return IPCOM_SUCCESS;
|
|
}
|
|
|
|
#else
|
|
int ipssh_sftp_empty_file;
|
|
#endif /* IPSSH_USE_SFTP */
|
|
|
|
|
|
/*
|
|
****************************************************************************
|
|
* END OF FILE
|
|
****************************************************************************
|
|
*/
|