Merge pull request #436 from ejohnstown/sftp-list

pull/466/head
Hayden Roche 2022-09-27 16:31:57 -07:00 committed by GitHub
commit 6f57587249
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 487 additions and 384 deletions

View File

@ -2030,6 +2030,57 @@ static int wsUserAuth(byte authType,
}
#ifdef WOLFSSH_SFTP
/*
* Sets the WOLFSSH object's default SFTP path to the value provided by
* defaultSftpPath, or uses the current working directory from where the
* echoserver is run. The new default path is cleaned up with the real
* path function.
*
* @param ssh WOLFSSH object to update
* @param defaultSftpPath command line provided default SFTP path
* @return 0 for success or error code
*/
static int SetDefaultSftpPath(WOLFSSH* ssh, const char* defaultSftpPath)
{
char path[WOLFSSH_MAX_FILENAME];
char realPath[WOLFSSH_MAX_FILENAME];
int ret = 0;
if (defaultSftpPath == NULL) {
#ifdef USE_WINDOWS_API
if (GetCurrentDirectoryA(sizeof(path)-1, path) == 0) {
ret = WS_INVALID_PATH_E;
}
#else
if (getcwd(path, sizeof(path)-1) == NULL) {
ret = WS_INVALID_PATH_E;
}
#endif
}
else {
if (WSTRLEN(defaultSftpPath) >= sizeof(path)) {
ret = WS_INVALID_PATH_E;
}
else {
WSTRNCPY(path, defaultSftpPath, sizeof(path));
}
}
if (ret == 0) {
path[sizeof(path) - 1] = 0;
ret = wolfSSH_RealPath(NULL, path, realPath, sizeof(realPath));
}
if (ret == WS_SUCCESS) {
ret = wolfSSH_SFTP_SetDefaultPath(ssh, realPath);
}
return ret;
}
#endif
static void ShowUsage(void)
{
printf("echoserver %s\n", LIBWOLFSSH_VERSION_STRING);
@ -2451,12 +2502,9 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args)
}
#ifdef WOLFSSH_SFTP
if (defaultSftpPath) {
if (wolfSSH_SFTP_SetDefaultPath(ssh, defaultSftpPath)
!= WS_SUCCESS) {
fprintf(stderr, "Couldn't store default sftp path.\n");
WEXIT(EXIT_FAILURE);
}
if (SetDefaultSftpPath(ssh, defaultSftpPath) != 0) {
fprintf(stderr, "Couldn't store default sftp path.\n");
WEXIT(EXIT_FAILURE);
}
#endif

View File

@ -166,6 +166,25 @@ int wfopen(WFILE** f, const char* filename, const char* mode)
#if defined(USE_WINDOWS_API) && (defined(WOLFSSH_SFTP) || defined(WOLFSSH_SCP))
/*
* SFTP paths all start with a leading root "/". Most Windows file routines
* expect a drive letter when dealing with an absolute path. If the provided
* path, f, is of the form "/C:...", adjust the pointer f to point to the "C",
* and decrement the file path size, fSz, by one.
*
* @param f pointer to a file name
* @param fSz size of f in bytes
* @return pointer to somewhere in f
*/
static const char* TrimFileName(const char* f, size_t* fSz)
{
if (f != NULL && fSz != NULL && *fSz >= 3 && f[0] == '/' && f[2] == ':') {
f++;
*fSz--;
}
return f;
}
void* WS_CreateFileA(const char* fileName, unsigned long desiredAccess,
unsigned long shareMode, unsigned long creationDisposition,
unsigned long flags, void* heap)
@ -178,6 +197,8 @@ void* WS_CreateFileA(const char* fileName, unsigned long desiredAccess,
errno_t error;
fileNameSz = WSTRLEN(fileName);
fileName = TrimFileName(fileName, &fileNameSz);
error = mbstowcs_s(&unicodeFileNameSz, NULL, 0, fileName, 0);
if (error)
return INVALID_HANDLE_VALUE;
@ -211,6 +232,8 @@ void* WS_FindFirstFileA(const char* fileName,
errno_t error;
fileNameSz = WSTRLEN(fileName);
fileName = TrimFileName(fileName, &fileNameSz);
error = mbstowcs_s(&unicodeFileNameSz, NULL, 0, fileName, 0);
if (error)
return INVALID_HANDLE_VALUE;
@ -268,6 +291,8 @@ int WS_GetFileAttributesExA(const char* fileName, void* fileInfo, void* heap)
errno_t error;
fileNameSz = WSTRLEN(fileName);
fileName = TrimFileName(fileName, &fileNameSz);
error = mbstowcs_s(&unicodeFileNameSz, NULL, 0, fileName, 0);
if (error != 0)
return 0;
@ -301,6 +326,8 @@ int WS_RemoveDirectoryA(const char* dirName, void* heap)
errno_t error;
dirNameSz = WSTRLEN(dirName);
dirName = TrimFileName(dirName, &dirNameSz);
error = mbstowcs_s(&unicodeDirNameSz, NULL, 0, dirName, 0);
if (error != 0)
return 0;
@ -333,6 +360,8 @@ int WS_CreateDirectoryA(const char* dirName, void* heap)
errno_t error;
dirNameSz = WSTRLEN(dirName);
dirName = TrimFileName(dirName, &dirNameSz);
error = mbstowcs_s(&unicodeDirNameSz, NULL, 0, dirName, 0);
if (error != 0)
return 0;
@ -368,6 +397,7 @@ int WS_MoveFileA(const char* oldName, const char* newName, void* heap)
errno_t error;
oldNameSz = WSTRLEN(oldName);
oldName = TrimFileName(oldName, &oldNameSz);
error = mbstowcs_s(&unicodeOldNameSz, NULL, 0, oldName, 0);
if (error != 0)
@ -382,6 +412,8 @@ int WS_MoveFileA(const char* oldName, const char* newName, void* heap)
oldName, oldNameSz);
newNameSz = WSTRLEN(newName);
newName = TrimFileName(newName, &newNameSz);
error = mbstowcs_s(&unicodeNewNameSz, NULL, 0, newName, 0);
if (error != 0)
return 0;
@ -417,6 +449,8 @@ int WS_DeleteFileA(const char* fileName, void* heap)
errno_t error;
fileNameSz = WSTRLEN(fileName);
fileName = TrimFileName(fileName, &fileNameSz);
error = mbstowcs_s(&unicodeFileNameSz, NULL, 0, fileName, 0);
if (error != 0)
return 0;

View File

@ -2274,9 +2274,14 @@ int wolfSSH_ChannelGetEof(WOLFSSH_CHANNEL* channel)
#if (defined(WOLFSSH_SFTP) || defined(WOLFSSH_SCP)) && \
!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 root. Any path that
* doesn't have a starting slash is assumed to be relative to the current
* 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
* path. If the path is empty, return the default path.
*
* The path "/." is stripped out. The path "/.." strips out the previous
@ -2284,7 +2289,7 @@ int wolfSSH_ChannelGetEof(WOLFSSH_CHANNEL* channel)
*
* Example: "/home/fred/frob/frizz/../../../barney/bar/baz/./././../.."
* will return "/home/barney". "/../.." will return "/". "." will return
* currentPath.
* the default path.
*
* Note, this function does not care about OS and filesystem issues. The
* SFTP protocol describes how paths are handled in SFTP. Specialized
@ -2292,39 +2297,41 @@ int wolfSSH_ChannelGetEof(WOLFSSH_CHANNEL* channel)
* are further massaged there. For example, the C: drive is treated as
* the path "/C:", and is a directory like any other.
*
* @param currentPath RealPath of the current working directory
* @param defaultPath RealPath of the default directory, usually user's
* @param in requested new path
* @param out output of real path cleanup
* @param outSz size in bytes of buffer 'out'
* @return WS_SUCCESS, WS_BAD_ARGUMENT, or WS_INVALID_PATH_E
*/
int wolfSSH_RealPath(const char* currentPath, const char* defaultPath,
char* in, char* out, word32 outSz)
int wolfSSH_RealPath(const char* defaultPath, char* in,
char* out, word32 outSz)
{
char* tail = NULL;
char* seg;
word32 inSz, segSz, curSz;
if (currentPath == NULL || defaultPath == NULL ||
in == NULL || out == NULL || outSz == 0)
if (in == NULL || out == NULL || outSz == 0) {
return WS_BAD_ARGUMENT;
}
WMEMSET(out, 0, outSz);
inSz = (word32)WSTRLEN(in);
if (inSz == 0) {
WSTRNCPY(out, defaultPath, outSz);
out[0] = '/';
curSz = 1;
if (inSz == 0 || (!IS_DELIM(in[0]) && !IS_WINPATH(inSz, in))) {
if (defaultPath != NULL) {
curSz = (word32)WSTRLEN(defaultPath);
if (curSz >= outSz) {
return WS_INVALID_PATH_E;
}
WSTRNCPY(out, defaultPath, outSz);
}
}
else if (in[0] == '/') {
out[0] = '/';
}
else {
WSTRNCPY(out, currentPath, outSz);
}
out[outSz - 1] = 0;
curSz = (word32)WSTRLEN(out);
out[curSz] = 0;
for (seg = WSTRTOK(in, "/", &tail); seg; seg = WSTRTOK(NULL, "/", &tail)) {
for (seg = WSTRTOK(in, DELIM, &tail);
seg;
seg = WSTRTOK(NULL, DELIM, &tail)) {
segSz = (word32)WSTRLEN(seg);
/* Try to match "." */
@ -2349,6 +2356,10 @@ int wolfSSH_RealPath(const char* currentPath, const char* defaultPath,
}
/* Everything else is copied */
else {
if (curSz >= outSz - segSz) {
return WS_INVALID_PATH_E;
}
if (curSz != 1) {
WSTRNCAT(out, "/", outSz - curSz);
curSz++;

File diff suppressed because it is too large Load Diff

View File

@ -1021,7 +1021,7 @@ struct RealPathTestCase {
const char* exp;
};
struct RealPathTestCase realPathTestCases[] = {
struct RealPathTestCase realPathDefault[] = {
{ ".", "/C:/Users/fred" },
{ "", "/C:/Users/fred" },
{ "/C:/Users/fred/..", "/C:/Users" },
@ -1042,33 +1042,106 @@ struct RealPathTestCase realPathTestCases[] = {
{ "/home/C:/ok", "/home/C:/ok" },
{ "/home/fred/frob/frizz/../../../barney/bar/baz/./././../..",
"/home/barney" },
{ "/home/fred/sample.", "/home/fred/sample." },
{ "/home/fred/sample.jpg", "/home/fred/sample.jpg" },
{ "/home/fred/sample./other", "/home/fred/sample./other" },
{ "/home/fred/sample.dir/other", "/home/fred/sample.dir/other" },
{ "./sample.", "/C:/Users/fred/sample." },
{ "./sample.jpg", "/C:/Users/fred/sample.jpg" },
{ "./sample./other", "/C:/Users/fred/sample./other" },
{ "./sample.dir/other", "/C:/Users/fred/sample.dir/other" },
{ "\\C:\\Users\\fred\\Documents\\junk.txt",
"/C:/Users/fred/Documents/junk.txt" },
{ "C:\\Users\\fred\\Documents\\junk.txt",
"/C:/Users/fred/Documents/junk.txt" },
{ "/C:\\Users\\fred/Documents\\junk.txt",
"/C:/Users/fred/Documents/junk.txt" },
};
const char* defaultPath = "/C:/Users/fred";
struct RealPathTestCase realPathNull[] = {
{ ".", "/" },
{ "", "/" },
{ "..", "/" },
{ "../barney", "/barney" },
};
static void DoRealPathTestCase(const char* path, struct RealPathTestCase* tc)
{
char testPath[128];
char checkPath[128];
int err;
WSTRNCPY(testPath, tc->in, sizeof(testPath) - 1);
testPath[sizeof(testPath) - 1] = 0;
WMEMSET(checkPath, 0, sizeof checkPath);
err = wolfSSH_RealPath(path, testPath,
checkPath, sizeof checkPath);
if (err || WSTRCMP(tc->exp, checkPath) != 0) {
fprintf(stderr, "RealPath failure (%d)\n"
" defaultPath: %s\n"
" input: %s\n"
" expected: %s\n"
" output: %s\n", err,
path, tc->in, tc->exp, checkPath);
}
}
struct RealPathTestFailCase {
const char* defaultPath;
const char* in;
word32 checkPathSz;
int expErr;
};
struct RealPathTestFailCase realPathFail[] = {
/* Output size less than default path length. */
{ "12345678", "12345678", 4, WS_INVALID_PATH_E },
/* Output size equal to default path length. */
{ "12345678", "12345678", 8, WS_INVALID_PATH_E },
/* Copy segment will not fit in output. */
{ "1234567", "12345678", 8, WS_INVALID_PATH_E },
};
static void DoRealPathTestFailCase(struct RealPathTestFailCase* tc)
{
char testPath[128];
char checkPath[128];
int err;
WSTRNCPY(testPath, tc->in, sizeof(testPath) - 1);
testPath[sizeof(testPath) - 1] = 0;
WMEMSET(checkPath, 0, sizeof checkPath);
err = wolfSSH_RealPath(tc->defaultPath, testPath,
checkPath, tc->checkPathSz);
if (err != tc->expErr) {
fprintf(stderr, "RealPath fail check failure (%d)\n"
" defaultPath: %s\n"
" input: %s\n"
" checkPathSz: %u\n"
" expected: %d\n", err,
tc->defaultPath, tc->in, tc->checkPathSz, tc->expErr);
}
}
static void test_wolfSSH_RealPath(void)
{
struct RealPathTestCase* tc;
char testPath[128];
char checkPath[128];
word32 testCount =
(sizeof realPathTestCases)/(sizeof(struct RealPathTestCase));
word32 testCount;
word32 i;
int err;
for (i = 0, tc = realPathTestCases; i < testCount; i++, tc++) {
WSTRNCPY(testPath, tc->in, sizeof(testPath) - 1);
testPath[sizeof(testPath) - 1] = 0;
WMEMSET(checkPath, 0, sizeof checkPath);
err = wolfSSH_RealPath(defaultPath, defaultPath, testPath,
checkPath, sizeof checkPath);
if (err || WSTRCMP(tc->exp, checkPath) != 0) {
printf("RealPath failure (case %u: %d)\n"
" defaultPath: %s\n"
" input: %s\n"
" expected: %s\n"
" output: %s\n", i, err,
defaultPath, tc->in, tc->exp, checkPath);
}
testCount = (sizeof realPathDefault)/(sizeof(struct RealPathTestCase));
for (i = 0; i < testCount; i++) {
DoRealPathTestCase("/C:/Users/fred", realPathDefault + i);
}
testCount = (sizeof realPathNull)/(sizeof(struct RealPathTestCase));
for (i = 0; i < testCount; i++) {
DoRealPathTestCase(NULL, realPathNull + i);
}
testCount = (sizeof realPathFail)/(sizeof(struct RealPathTestFailCase));
for (i = 0; i < testCount; i++) {
DoRealPathTestFailCase(realPathFail + i);
}
}
#else
@ -1088,7 +1161,6 @@ int main(void)
test_wolfSSH_SetUsername();
test_wolfSSH_ConvertConsole();
test_wolfSSH_CTX_UsePrivateKey_buffer();
test_wolfSSH_RealPath();
test_wolfSSH_CTX_UseCert_buffer();
test_wolfSSH_CertMan();
@ -1098,6 +1170,8 @@ int main(void)
/* SFTP tests */
test_wolfSSH_SFTP_SendReadPacket();
/* Either SCP or SFTP */
test_wolfSSH_RealPath();
AssertIntEQ(wolfSSH_Cleanup(), WS_SUCCESS);

View File

@ -540,7 +540,11 @@ struct WS_SFTP_GET_HANDLE_STATE;
struct WS_SFTP_PUT_STATE;
struct WS_SFTP_RENAME_STATE;
#ifdef USE_WINDOWS_API
#define MAX_DRIVE_LETTER 26
#endif /* USE_WINDOWS_API */
#endif /* WOLFSSH_SFTP */
#ifdef USE_WINDOWS_API
#ifndef WOLFSSL_MAX_ESCBUF
#define WOLFSSL_MAX_ESCBUF 19
@ -717,6 +721,11 @@ struct WOLFSSH {
struct WS_SFTP_SEND_WRITE_STATE* sendWriteState;
struct WS_SFTP_GET_HANDLE_STATE* getHandleState;
struct WS_SFTP_RENAME_STATE* renameState;
#ifdef USE_WINDOWS_API
char driveList[MAX_DRIVE_LETTER];
word16 driveListCount;
word16 driveIdx;
#endif
#endif
#ifdef WOLFSSH_AGENT

View File

@ -339,8 +339,8 @@ enum WS_DisconnectReasonCodes {
};
WOLFSSH_API int wolfSSH_RealPath(const char* currentPath,
const char* defaultPath, char* in, char* out, word32 outSz);
WOLFSSH_API int wolfSSH_RealPath(const char* defaultPath, char* in,
char* out, word32 outSz);
WOLFSSH_API void wolfSSH_ShowSizes(void);