keep trailing delimiter with SFTP open

pull/743/head
JacobBarthelmeh 2024-09-30 15:49:33 -06:00
parent 3cabbdb703
commit 52e4e32529
7 changed files with 118 additions and 16 deletions

View File

@ -60,6 +60,7 @@ run_test() {
run_test "sshd_exec_test.sh" run_test "sshd_exec_test.sh"
run_test "sshd_term_size_test.sh" run_test "sshd_term_size_test.sh"
run_test "sshd_large_sftp_test.sh" run_test "sshd_large_sftp_test.sh"
run_test "sshd_bad_sftp_test.sh"
#Github actions needs resolved for these test cases #Github actions needs resolved for these test cases
#run_test "error_return.sh" #run_test "error_return.sh"

View File

@ -0,0 +1,34 @@
#!/bin/sh
# sshd local test
PWD=`pwd`
cd ../../..
TEST_SFTP_CLIENT="./examples/sftpclient/wolfsftp"
USER=`whoami`
PRIVATE_KEY="./keys/hansel-key-ecc.der"
PUBLIC_KEY="./keys/hansel-key-ecc.pub"
if [ -z "$1" ] || [ -z "$2" ]; then
echo "expecting host and port as arguments"
echo "./sshd_exec_test.sh 127.0.0.1 22222"
exit 1
fi
mkdir test-$$
mkdir test-$$/subfolder
echo "$TEST_SFTP_CLIENT -u $USER -i $PRIVATE_KEY -j $PUBLIC_KEY -g -l configure -r `pwd`/test-$$/subfolder/ -h \"$1\" -p \"$2\""
"$TEST_SFTP_CLIENT -u $USER -i $PRIVATE_KEY -j $PUBLIC_KEY -g -l configure -r `pwd`/test-$$/subfolder/ -h $1 -p $2"
RESULT=$?
if [ "$RESULT" = "0" ]; then
echo "Expecting to fail transfer to folder"
exit 1
fi
rm -rf test-$$
cd $PWD
exit 0

View File

@ -15686,6 +15686,57 @@ int SendChannelSuccess(WOLFSSH* ssh, word32 channelId, int success)
#if (defined(WOLFSSH_SFTP) || defined(WOLFSSH_SCP)) && \ #if (defined(WOLFSSH_SFTP) || defined(WOLFSSH_SCP)) && \
!defined(NO_WOLFSSH_SERVER) !defined(NO_WOLFSSH_SERVER)
/* Checks if 'in' is absolute path, if not the returns the concat. of
* 'defaultPath' | 'in'. This leaves 'in' as-is and does not handle
* simplification of the path, such as removing ../
*
* Sanity checks outSz and then adjusts it for the size used
* returns WS_SUCCESS on success
*/
int wolfSSH_GetPath(const char* defaultPath, byte* in, word32 inSz,
char* out, word32* outSz)
{
word32 curSz = 0;
if (out != NULL) {
WMEMSET(out, 0, *outSz);
}
if (inSz == 0 || (!WOLFSSH_SFTP_IS_DELIM(in[0]) &&
!WOLFSSH_SFTP_IS_WINPATH(inSz, in))) {
if (defaultPath != NULL) {
curSz = (word32)WSTRLEN(defaultPath);
if (out != NULL && curSz >= *outSz) {
return WS_INVALID_PATH_E;
}
if (out != NULL) {
WSTRNCPY(out, defaultPath, *outSz);
if (out[curSz] != '/') {
out[curSz] = '/';
curSz++;
}
}
}
}
if (out != NULL) {
WMEMCPY(out + curSz, in, inSz);
}
curSz += inSz;
if (out != NULL) {
if (!WOLFSSH_SFTP_IS_DELIM(out[0])) {
WMEMMOVE(out+1, out, curSz);
out[0] = '/';
curSz++;
}
out[curSz] = 0;
}
*outSz = curSz;
return WS_SUCCESS;
}
/* cleans up absolute path /* cleans up absolute path
* returns size of new path on success (strlen sz) and negative values on fail*/ * returns size of new path on success (strlen sz) and negative values on fail*/
int wolfSSH_CleanPath(WOLFSSH* ssh, char* in) int wolfSSH_CleanPath(WOLFSSH* ssh, char* in)

View File

@ -3276,10 +3276,6 @@ void* wolfSSH_GetChannelCloseCtx(WOLFSSH* ssh)
#if (defined(WOLFSSH_SFTP) || defined(WOLFSSH_SCP)) && \ #if (defined(WOLFSSH_SFTP) || defined(WOLFSSH_SCP)) && \
!defined(NO_WOLFSSH_SERVER) !defined(NO_WOLFSSH_SERVER)
#define DELIM "/\\"
#define IS_DELIM(x) ((x) == '/' || (x) == '\\')
#define IS_WINPATH(x,y) ((x) > 1 && (y)[1] == ':')
/* /*
* Paths starting with a slash are absolute, rooted at "/". Any path that * Paths starting with a slash are absolute, rooted at "/". Any path that
* doesn't have a starting slash is assumed to be relative to the default * doesn't have a starting slash is assumed to be relative to the default
@ -3288,6 +3284,8 @@ void* wolfSSH_GetChannelCloseCtx(WOLFSSH* ssh)
* The path "/." is stripped out. The path "/.." strips out the previous * The path "/." is stripped out. The path "/.." strips out the previous
* path value. The root path, "/", is always present. * path value. The root path, "/", is always present.
* *
* Trailing delimiters are stripped, i.e /tmp/path/ becomes /tmp/path
*
* Example: "/home/fred/frob/frizz/../../../barney/bar/baz/./././../.." * Example: "/home/fred/frob/frizz/../../../barney/bar/baz/./././../.."
* will return "/home/barney". "/../.." will return "/". "." will return * will return "/home/barney". "/../.." will return "/". "." will return
* the default path. * the default path.
@ -3319,7 +3317,8 @@ int wolfSSH_RealPath(const char* defaultPath, char* in,
inSz = (word32)WSTRLEN(in); inSz = (word32)WSTRLEN(in);
out[0] = '/'; out[0] = '/';
curSz = 1; curSz = 1;
if (inSz == 0 || (!IS_DELIM(in[0]) && !IS_WINPATH(inSz, in))) { if (inSz == 0 || (!WOLFSSH_SFTP_IS_DELIM(in[0]) &&
!WOLFSSH_SFTP_IS_WINPATH(inSz, in))) {
if (defaultPath != NULL) { if (defaultPath != NULL) {
curSz = (word32)WSTRLEN(defaultPath); curSz = (word32)WSTRLEN(defaultPath);
if (curSz >= outSz) { if (curSz >= outSz) {
@ -3330,9 +3329,9 @@ int wolfSSH_RealPath(const char* defaultPath, char* in,
} }
out[curSz] = 0; out[curSz] = 0;
for (seg = WSTRTOK(in, DELIM, &tail); for (seg = WSTRTOK(in, WOLFSSH_SFTP_DELIM, &tail);
seg; seg;
seg = WSTRTOK(NULL, DELIM, &tail)) { seg = WSTRTOK(NULL, WOLFSSH_SFTP_DELIM, &tail)) {
segSz = (word32)WSTRLEN(seg); segSz = (word32)WSTRLEN(seg);
/* Try to match "." */ /* Try to match "." */

View File

@ -1974,7 +1974,7 @@ int wolfSSH_SFTP_RecvOpen(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
{ {
WS_SFTP_FILEATRB atr; WS_SFTP_FILEATRB atr;
WFD fd; WFD fd;
word32 sz; word32 sz, dirSz;
char dir[WOLFSSH_MAX_FILENAME]; char dir[WOLFSSH_MAX_FILENAME];
word32 reason; word32 reason;
word32 idx = 0; word32 idx = 0;
@ -2010,10 +2010,11 @@ int wolfSSH_SFTP_RecvOpen(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
return WS_BUFFER_E; return WS_BUFFER_E;
} }
ret = GetAndCleanPath(ssh->sftpDefaultPath, data + idx, sz, dirSz = sizeof(dir);
dir, sizeof(dir)); if (wolfSSH_GetPath(ssh->sftpDefaultPath, data + idx, sz, dir, &dirSz)
if (ret < 0) { != WS_SUCCESS) {
return ret; WLOG(WS_LOG_SFTP, "Creating path for file to open failed");
return WS_FATAL_ERROR;
} }
idx += sz; idx += sz;
@ -2128,7 +2129,7 @@ int wolfSSH_SFTP_RecvOpen(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
{ {
/* WS_SFTP_FILEATRB atr;*/ /* WS_SFTP_FILEATRB atr;*/
HANDLE fileHandle; HANDLE fileHandle;
word32 sz; word32 sz, dirSz;
char dir[WOLFSSH_MAX_FILENAME]; char dir[WOLFSSH_MAX_FILENAME];
word32 reason; word32 reason;
word32 idx = 0; word32 idx = 0;
@ -2165,9 +2166,11 @@ int wolfSSH_SFTP_RecvOpen(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
return WS_BUFFER_E; return WS_BUFFER_E;
} }
if (GetAndCleanPath(ssh->sftpDefaultPath, dirSz = sizeof(dir);
data + idx, sz, dir, sizeof(dir)) < 0) { if (wolfSSH_GetPath(ssh->sftpDefaultPath, data + idx, sz, dir, &dirSz)
return WS_BUFFER_E; != WS_SUCCESS) {
WLOG(WS_LOG_SFTP, "Creating path for file to open failed");
return WS_FATAL_ERROR;
} }
idx += sz; idx += sz;

View File

@ -620,6 +620,12 @@ typedef struct HandshakeInfo {
} privKey; } privKey;
} HandshakeInfo; } HandshakeInfo;
#if (defined(WOLFSSH_SFTP) || defined(WOLFSSH_SCP)) && \
!defined(NO_WOLFSSH_SERVER)
WOLFSSH_LOCAL int wolfSSH_GetPath(const char* defaultPath, byte* in,
word32 inSz, char* out, word32* outSz);
#endif
#ifdef WOLFSSH_SFTP #ifdef WOLFSSH_SFTP
#define WOLFSSH_MAX_SFTPOFST 3 #define WOLFSSH_MAX_SFTPOFST 3

View File

@ -575,6 +575,14 @@ extern "C" {
#define WLOCALTIME(c,r) (localtime_r((c),(r))!=NULL) #define WLOCALTIME(c,r) (localtime_r((c),(r))!=NULL)
#endif #endif
#ifndef WOLFSSH_SFTP_DELIM
/* Delimiter's used between two SFTP peers should be the same regardless of
* operating system. WS_DELIM defined elsewhere is OS specific delimiter. */
#define WOLFSSH_SFTP_DELIM "/\\"
#define WOLFSSH_SFTP_IS_DELIM(x) ((x) == '/' || (x) == '\\')
#define WOLFSSH_SFTP_IS_WINPATH(x,y) ((x) > 1 && (y)[1] == ':')
#endif
#if (defined(WOLFSSH_SFTP) || \ #if (defined(WOLFSSH_SFTP) || \
defined(WOLFSSH_SCP) || defined(WOLFSSH_SSHD)) && \ defined(WOLFSSH_SCP) || defined(WOLFSSH_SSHD)) && \
!defined(NO_WOLFSSH_SERVER) && !defined(NO_FILESYSTEM) !defined(NO_WOLFSSH_SERVER) && !defined(NO_FILESYSTEM)