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,13 +2502,10 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args)
}
#ifdef WOLFSSH_SFTP
if (defaultSftpPath) {
if (wolfSSH_SFTP_SetDefaultPath(ssh, defaultSftpPath)
!= WS_SUCCESS) {
if (SetDefaultSftpPath(ssh, defaultSftpPath) != 0) {
fprintf(stderr, "Couldn't store default sftp path.\n");
WEXIT(EXIT_FAILURE);
}
}
#endif
#ifdef WOLFSSL_NUCLEUS

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) {
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++;

View File

@ -1151,9 +1151,9 @@ static int wolfSSH_SFTP_RecvRealPath(WOLFSSH* ssh, int reqId, byte* data,
{
WS_SFTP_FILEATRB atr;
char r[WOLFSSH_MAX_FILENAME];
word32 rSz;
char s[WOLFSSH_MAX_FILENAME];
word32 rSz, sSz;
word32 lidx = 0;
word32 i;
int ret;
byte* out;
word32 outSz = 0;
@ -1177,18 +1177,35 @@ static int wolfSSH_SFTP_RecvRealPath(WOLFSSH* ssh, int reqId, byte* data,
lidx += UINT32_SZ;
WMEMCPY(r, data + lidx, rSz);
r[rSz] = '\0';
WLOG(WS_LOG_SFTP, "Real Path Request = %s", r);
/* get working directory in the case of receiving non absolute path */
if (r[0] != '/' && r[1] != ':') {
/* If the default path isn't set, try to get it. */
if (ssh->sftpDefaultPath == NULL) {
char wd[WOLFSSH_MAX_FILENAME];
WMEMSET(wd, 0, WOLFSSH_MAX_FILENAME);
if (ssh->sftpDefaultPath) {
XSTRNCPY(wd, ssh->sftpDefaultPath, WOLFSSH_MAX_FILENAME - 1);
}
else {
ret = WS_SUCCESS;
#ifndef USE_WINDOWS_API
if (WGETCWD(ssh->fs, wd, WOLFSSH_MAX_FILENAME) == NULL) {
if (WGETCWD(ssh->fs, wd, sizeof(wd)-1) == NULL) {
ret = WS_INVALID_PATH_E;
}
#else
if (GetCurrentDirectoryA(sizeof(wd)-1, wd) == 0) {
ret = WS_INVALID_PATH_E;
}
#endif
if (ret == WS_SUCCESS) {
wd[sizeof(wd) - 1] = 0;
ret = wolfSSH_RealPath(NULL, wd, s, sizeof s);
}
if (ret == WS_SUCCESS) {
ret = wolfSSH_SFTP_SetDefaultPath(ssh, s);
}
}
/* If the default path still isn't set, send error to peer. */
if (ssh->sftpDefaultPath == NULL) {
WLOG(WS_LOG_SFTP, "Unable to get current working directory");
if (wolfSSH_SFTP_CreateStatus(ssh, WOLFSSH_FTP_FAILURE, reqId,
"Directory error", "English", NULL, &outSz)
@ -1207,43 +1224,19 @@ static int wolfSSH_SFTP_RecvRealPath(WOLFSSH* ssh, int reqId, byte* data,
}
/* take over control of buffer */
wolfSSH_SFTP_RecvSetSend(ssh, out, outSz);
return WS_BAD_FILE_E;
}
#endif
}
WSTRNCAT(wd, "/", WOLFSSH_MAX_FILENAME);
WSTRNCAT(wd, r, WOLFSSH_MAX_FILENAME);
WMEMCPY(r, wd, WOLFSSH_MAX_FILENAME);
return ret;
}
if ((ret = wolfSSH_CleanPath(ssh, r)) < 0) {
return WS_FATAL_ERROR;
ret = wolfSSH_RealPath(ssh->sftpDefaultPath, r, s, sizeof s);
if (ret != WS_SUCCESS) {
return ret;
}
rSz = (word32)ret;
sSz = (word32)WSTRLEN(s);
/* For real path remove ending case of /.
* Lots of peers send a '.' wanting a return of the current absolute path
* not the absolute path + .
*/
if (rSz > 2 && r[rSz - 2] == WS_DELIM && r[rSz - 1] == '.') {
r[rSz - 1] = '\0';
rSz -= 1;
}
/* special case of /. */
if (rSz == 2 && r[0] == WS_DELIM && r[1] == '.') {
r[1] = '\0';
rSz -= 1;
}
/* for real path always send '/' chars */
for (i = 0; i < rSz; i++) {
if (r[i] == WS_DELIM) r[i] = '/';
}
WLOG(WS_LOG_SFTP, "Real Path Directory = %s", r);
WLOG(WS_LOG_SFTP, "Real Path Directory = %s", s);
/* send response */
outSz = WOLFSSH_SFTP_HEADER + (UINT32_SZ * 3) + (rSz * 2);
outSz = WOLFSSH_SFTP_HEADER + (UINT32_SZ * 3) + (sSz * 2);
WMEMSET(&atr, 0, sizeof(WS_SFTP_FILEATRB));
outSz += SFTP_AtributesSz(ssh, &atr);
lidx = 0;
@ -1264,12 +1257,12 @@ static int wolfSSH_SFTP_RecvRealPath(WOLFSSH* ssh, int reqId, byte* data,
c32toa(1, out + lidx); lidx += UINT32_SZ; /* only sending one file name */
/* set file name size and string */
c32toa(rSz, out + lidx); lidx += UINT32_SZ;
WMEMCPY(out + lidx, r, rSz); lidx += rSz;
c32toa(sSz, out + lidx); lidx += UINT32_SZ;
WMEMCPY(out + lidx, s, sSz); lidx += sSz;
/* set long name size and string */
c32toa(rSz, out + lidx); lidx += UINT32_SZ;
WMEMCPY(out + lidx, r, rSz); lidx += rSz;
c32toa(sSz, out + lidx); lidx += UINT32_SZ;
WMEMCPY(out + lidx, s, sSz); lidx += sSz;
/* set attributes */
SFTP_SetAttributes(ssh, out + lidx, outSz - lidx, &atr);
@ -1577,6 +1570,32 @@ int wolfSSH_SFTP_CreateStatus(WOLFSSH* ssh, word32 status, word32 reqId,
}
/*
* This is a wrapper around the function wolfSSH_RealPath. Since it modifies
* the source path value, copy the path from the data stream into a local
* array and use that as the source.
*
* @param defaultPath pointer to the defaultPath
* @param data input data stream at the location of the path name
* @param sz size of the path name in bytes
* @param s destination buffer for the Real Path
* @param sSz size of s in bytes
* @return 0 for success or negative error code
*/
static int GetAndCleanPath(const char* defaultPath,
const byte* data, word32 sz, char* s, word32 sSz)
{
char r[WOLFSSH_MAX_FILENAME];
if (sz >= sizeof r)
return WS_BUFFER_E;
WMEMCPY(r, data, sz);
r[sz] = '\0';
return wolfSSH_RealPath(defaultPath, r, s, sSz);
}
/* Handles packet to remove a directory
*
* returns WS_SUCCESS on success
@ -1585,7 +1604,7 @@ int wolfSSH_SFTP_RecvRMDIR(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
{
word32 sz;
int ret = 0;
char* dir;
char dir[WOLFSSH_MAX_FILENAME];
word32 idx = 0;
byte* out;
word32 outSz = 0;
@ -1606,17 +1625,8 @@ int wolfSSH_SFTP_RecvRMDIR(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
return WS_BUFFER_E;
}
/* plus one to make sure is null terminated */
dir = (char*)WMALLOC(sz + 1, ssh->ctx->heap, DYNTYPE_BUFFER);
if (dir == NULL) {
return WS_MEMORY_E;
}
WMEMCPY(dir, data + idx, sz);
dir[sz] = '\0';
if (wolfSSH_CleanPath(ssh, dir) < 0) {
ret = WS_FATAL_ERROR;
}
ret = GetAndCleanPath(ssh->sftpDefaultPath,
data + idx, sz, dir, sizeof(dir));
if (ret == 0) {
#ifndef USE_WINDOWS_API
@ -1625,7 +1635,6 @@ int wolfSSH_SFTP_RecvRMDIR(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
ret = WS_RemoveDirectoryA(dir, ssh->ctx->heap) == 0;
#endif /* USE_WINDOWS_API */
}
WFREE(dir, ssh->ctx->heap, DYNTYPE_BUFFER);
res = (ret != 0)? err : suc;
type = (ret != 0)? WOLFSSH_FTP_FAILURE : WOLFSSH_FTP_OK;
@ -1669,7 +1678,7 @@ int wolfSSH_SFTP_RecvMKDIR(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
{
word32 sz;
int ret;
char* dir;
char dir[WOLFSSH_MAX_FILENAME];
word32 mode = 0;
word32 idx = 0;
byte* out;
@ -1680,7 +1689,6 @@ int wolfSSH_SFTP_RecvMKDIR(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
char suc[] = "Created Directory";
char* res = NULL;
if (ssh == NULL) {
return WS_BAD_ARGUMENT;
}
@ -1692,22 +1700,19 @@ int wolfSSH_SFTP_RecvMKDIR(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
return WS_BUFFER_E;
}
/* plus one to make sure is null terminated */
dir = (char*)WMALLOC(sz + 1, ssh->ctx->heap, DYNTYPE_BUFFER);
if (dir == NULL) {
return WS_MEMORY_E;
ret = GetAndCleanPath(ssh->sftpDefaultPath,
data + idx, sz, dir, sizeof(dir));
if (ret != WS_SUCCESS) {
return ret;
}
WMEMCPY(dir, data + idx, sz);
dir[sz] = '\0';
idx += sz;
if (idx + UINT32_SZ > maxSz) {
WFREE(dir, ssh->ctx->heap, DYNTYPE_BUFFER);
return WS_BUFFER_E;
}
ato32(data + idx, &sz); idx += UINT32_SZ;
if (sz > maxSz - idx) {
WFREE(dir, ssh->ctx->heap, DYNTYPE_BUFFER);
return WS_BUFFER_E;
}
if (sz != UINT32_SZ) {
@ -1719,17 +1724,11 @@ int wolfSSH_SFTP_RecvMKDIR(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
ato32(data + idx, &mode);
}
if (wolfSSH_CleanPath(ssh, dir) < 0) {
WFREE(dir, ssh->ctx->heap, DYNTYPE_BUFFER);
return WS_FATAL_ERROR;
}
#ifndef USE_WINDOWS_API
ret = WMKDIR(ssh->fs, dir, mode);
#else /* USE_WINDOWS_API */
ret = WS_CreateDirectoryA(dir, ssh->ctx->heap) == 0;
#endif /* USE_WINDOWS_API */
WFREE(dir, ssh->ctx->heap, DYNTYPE_BUFFER);
res = (ret != 0)? err : suc;
type = (ret != 0)? WOLFSSH_FTP_FAILURE : WOLFSSH_FTP_OK;
@ -1871,7 +1870,7 @@ int wolfSSH_SFTP_RecvOpen(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
WS_SFTP_FILEATRB atr;
WFD fd;
word32 sz;
char* dir;
char dir[WOLFSSH_MAX_FILENAME];
word32 reason;
word32 idx = 0;
int m = 0;
@ -1900,13 +1899,11 @@ int wolfSSH_SFTP_RecvOpen(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
return WS_BUFFER_E;
}
/* plus one to make sure is null terminated */
dir = (char*)WMALLOC(sz + 1, ssh->ctx->heap, DYNTYPE_BUFFER);
if (dir == NULL) {
return WS_MEMORY_E;
ret = GetAndCleanPath(ssh->sftpDefaultPath, data + idx, sz,
dir, sizeof(dir));
if (ret < 0) {
return ret;
}
WMEMCPY(dir, data + idx, sz);
dir[sz] = '\0';
idx += sz;
/* get reason for opening file */
@ -1944,17 +1941,12 @@ int wolfSSH_SFTP_RecvOpen(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
atr.per = 0644;
}
if (wolfSSH_CleanPath(ssh, dir) < 0) {
WFREE(dir, ssh->ctx->heap, DYNTYPE_BUFFER);
return WS_FATAL_ERROR;
}
fd = WOPEN(dir, m, atr.per);
if (fd < 0) {
WLOG(WS_LOG_SFTP, "Error opening file %s", dir);
res = oer;
if (wolfSSH_SFTP_CreateStatus(ssh, WOLFSSH_FTP_FAILURE, reqId, res,
"English", NULL, &outSz) != WS_SIZE_ONLY) {
WFREE(dir, ssh->ctx->heap, DYNTYPE_BUFFER);
return WS_FATAL_ERROR;
}
ret = WS_BAD_FILE_E;
@ -1967,14 +1959,12 @@ int wolfSSH_SFTP_RecvOpen(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
res = ier;
if (wolfSSH_SFTP_CreateStatus(ssh, WOLFSSH_FTP_FAILURE, reqId, res,
"English", NULL, &outSz) != WS_SIZE_ONLY) {
WFREE(dir, ssh->ctx->heap, DYNTYPE_BUFFER);
return WS_FATAL_ERROR;
}
ret = WS_FATAL_ERROR;
}
}
#endif
WFREE(dir, ssh->ctx->heap, DYNTYPE_BUFFER);
/* create packet */
out = (byte*)WMALLOC(outSz, ssh->ctx->heap, DYNTYPE_BUFFER);
@ -2006,7 +1996,7 @@ int wolfSSH_SFTP_RecvOpen(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
/* WS_SFTP_FILEATRB atr;*/
HANDLE fileHandle;
word32 sz;
char* dir;
char dir[WOLFSSH_MAX_FILENAME];
word32 reason;
word32 idx = 0;
DWORD desiredAccess = 0;
@ -2037,13 +2027,10 @@ int wolfSSH_SFTP_RecvOpen(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
return WS_BUFFER_E;
}
/* plus one to make sure is null terminated */
dir = (char*)WMALLOC(sz + 1, ssh->ctx->heap, DYNTYPE_BUFFER);
if (dir == NULL) {
return WS_MEMORY_E;
if (GetAndCleanPath(ssh->sftpDefaultPath,
data + idx, sz, dir, sizeof(dir)) < 0) {
return WS_BUFFER_E;
}
WMEMCPY(dir, data + idx, sz);
dir[sz] = '\0';
idx += sz;
/* get reason for opening file */
@ -2079,10 +2066,6 @@ int wolfSSH_SFTP_RecvOpen(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
}
#endif
if (wolfSSH_CleanPath(ssh, dir) < 0) {
return WS_FATAL_ERROR;
}
fileHandle = WS_CreateFileA(dir, desiredAccess, 0, creationDisp,
FILE_ATTRIBUTE_NORMAL, ssh->ctx->heap);
if (fileHandle == INVALID_HANDLE_VALUE) {
@ -2160,7 +2143,7 @@ int wolfSSH_SFTP_RecvOpenDir(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
{
WDIR ctx;
word32 sz;
char* dir;
char dir[WOLFSSH_MAX_FILENAME];
word32 idx = 0;
int ret = WS_SUCCESS;
@ -2186,23 +2169,13 @@ int wolfSSH_SFTP_RecvOpenDir(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
return WS_BUFFER_E;
}
/* plus one to make sure is null terminated */
dir = (char*)WMALLOC(sz + 1, ssh->ctx->heap, DYNTYPE_BUFFER);
if (dir == NULL) {
return WS_MEMORY_E;
}
WMEMCPY(dir, data + idx, sz);
dir[sz] = '\0';
/* get directory handle */
if (wolfSSH_CleanPath(ssh, dir) < 0) {
WFREE(dir, ssh->ctx->heap, DYNTYPE_BUFFER);
return WS_FATAL_ERROR;
if (GetAndCleanPath(ssh->sftpDefaultPath,
data + idx, sz, dir, sizeof(dir)) < 0) {
return WS_BUFFER_E;
}
if (WOPENDIR(ssh->fs, ssh->ctx->heap, &ctx, dir) != 0) {
WLOG(WS_LOG_SFTP, "Error with opening directory");
WFREE(dir, ssh->ctx->heap, DYNTYPE_BUFFER);
WLOG(WS_LOG_SFTP, "Error with opening directory: %s", dir);
if (wolfSSH_SFTP_CreateStatus(ssh, WOLFSSH_FTP_NOFILE, reqId,
"Unable To Open Directory", "English", NULL, &outSz)
!= WS_SIZE_ONLY) {
@ -2215,13 +2188,25 @@ int wolfSSH_SFTP_RecvOpenDir(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
/* add to directory list @TODO locking for thread safety */
if (ret == WS_SUCCESS) {
DIR_HANDLE* cur = (DIR_HANDLE*)WMALLOC(sizeof(DIR_HANDLE),
DIR_HANDLE* cur = NULL;
char* dirName = NULL;
word32 dirNameSz;
cur = (DIR_HANDLE*)WMALLOC(sizeof(DIR_HANDLE),
ssh->ctx->heap, DYNTYPE_SFTP);
if (cur == NULL) {
WFREE(dir, ssh->ctx->heap, DYNTYPE_BUFFER);
WCLOSEDIR(&ctx);
return WS_MEMORY_E;
}
dirNameSz = (word32)WSTRLEN(dir) + 1;
dirName = (char*)WMALLOC(dirNameSz,
ssh->ctx->heap, DYNTYPE_PATH);
if (dirName == NULL) {
WCLOSEDIR(&ctx);
WFREE(cur, ssh->ctx->heap, DYNTYPE_SFTP);
return WS_MEMORY_E;
}
WMEMCPY(dirName, dir, dirNameSz);
#ifdef WOLFSSL_NUCLEUS
WMEMCPY(&cur->dir, &ctx, sizeof(WDIR));
#else
@ -2235,7 +2220,7 @@ int wolfSSH_SFTP_RecvOpenDir(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
cur->isEof = 0;
cur->next = dirList;
dirList = cur;
dirList->dirName = dir; /* take over ownership of buffer */
dirList->dirName = dirName; /* take over ownership of buffer */
}
out = (byte*)WMALLOC(outSz, ssh->ctx->heap, DYNTYPE_BUFFER);
@ -2275,6 +2260,7 @@ int wolfSSH_SFTP_RecvOpenDir(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
byte* out = NULL;
word32 id[2];
byte idFlat[sizeof(word32) * 2];
char name[MAX_PATH];
if (ssh == NULL) {
return WS_BAD_ARGUMENT;
@ -2301,17 +2287,43 @@ int wolfSSH_SFTP_RecvOpenDir(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
}
WMEMCPY(dirName, data + idx, sz);
dirName[sz] = '\0';
if (wolfSSH_CleanPath(ssh, dirName) < 0) {
WFREE(dirName, ssh->ctx->heap, DYNTYPE_BUFFER);
/* Special case in Windows for the root directory above the drives. */
if (dirName[0] == '/' && dirName[1] == 0) {
DWORD drives, mask;
UINT driveType;
char driveName[] = " :\\";
int i;
WMEMSET(ssh->driveList, 0, sizeof ssh->driveList);
ssh->driveListCount = 0;
drives = GetLogicalDrives();
for (i = 0, mask = 1; i < (sizeof ssh->driveList); i++, mask <<= 1) {
if (drives & mask) {
driveName[0] = 'A' + i;
driveType = GetDriveTypeA(driveName);
if (driveType == DRIVE_FIXED || driveType == DRIVE_REMOTE) {
ssh->driveList[ssh->driveListCount++] = driveName[0];
}
}
}
ssh->driveIdx = 0;
}
else {
if (sz > MAX_PATH - 2) {
WLOG(WS_LOG_SFTP, "Path name is too long.");
return WS_FATAL_ERROR;
}
WSTRNCPY(name, dirName, MAX_PATH);
WSTRNCAT(name, "/*", MAX_PATH);
/* get directory handle */
findHandle = (HANDLE)WS_FindFirstFileA(dirName,
/* get directory handle - see if directory exists */
findHandle = (HANDLE)WS_FindFirstFileA(name,
realName, sizeof(realName), &isDir, ssh->ctx->heap);
if (findHandle == INVALID_HANDLE_VALUE || !isDir) {
WLOG(WS_LOG_SFTP, "Error with opening directory");
WLOG(WS_LOG_SFTP, "Error with opening directory: %s", name);
WFREE(dirName, ssh->ctx->heap, DYNTYPE_BUFFER);
if (wolfSSH_SFTP_CreateStatus(ssh, WOLFSSH_FTP_NOFILE, reqId,
@ -2321,7 +2333,9 @@ int wolfSSH_SFTP_RecvOpenDir(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
}
ret = WS_BAD_FILE_E;
}
if (findHandle != NULL && findHandle != INVALID_HANDLE_VALUE)
FindClose(findHandle);
}
(void)reqId;
@ -2547,40 +2561,36 @@ static int wolfSSH_SFTPNAME_readdir(WOLFSSH* ssh, WDIR* dir, WS_SFTPNAME* out,
out->fSz = sz;
{
char* buf;
int bufSz;
int tmpSz;
char r[WOLFSSH_MAX_FILENAME];
char s[WOLFSSH_MAX_FILENAME];
bufSz = out->fSz + WSTRLEN(dirName) + sizeof(WS_DELIM);
buf = (char*)WMALLOC(bufSz + 1, out->heap, DYNTYPE_SFTP);
if (buf == NULL) {
return WS_MEMORY_E;
}
buf[0] = '\0';
if (!special) { /* do not add dir name in special case */
WSTRNCAT(buf, dirName, bufSz + 1);
tmpSz = WSTRLEN(buf);
/* add delimiter between path and file/dir name */
if (tmpSz + 1 < bufSz) {
buf[tmpSz] = WS_DELIM;
buf[tmpSz+1] = '\0';
if (WSTRLEN(dirName) + out->fSz + 2 > (sizeof r)) {
WLOG(WS_LOG_SFTP, "Path length too large");
WFREE(out->fName, out->heap, DYNTYPE_SFTP);
return WS_FATAL_ERROR;
}
WSNPRINTF(r, sizeof(r), "%s/%s", dirName, out->fName);
}
else {
if (out->fSz + 1 > (sizeof r)) {
WLOG(WS_LOG_SFTP, "Path length too large");
WFREE(out->fName, out->heap, DYNTYPE_SFTP);
return WS_FATAL_ERROR;
}
WSTRNCPY(r, out->fName, sizeof(r));
}
}
WSTRNCAT(buf, out->fName, bufSz + 1);
if (wolfSSH_CleanPath(ssh, buf) < 0) {
if (wolfSSH_RealPath(ssh->sftpDefaultPath, r, s, sizeof(s)) < 0) {
WLOG(WS_LOG_SFTP, "Error cleaning path to get attributes");
WFREE(buf, out->heap, DYNTYPE_SFTP);
WFREE(out->fName, out->heap, DYNTYPE_SFTP);
return WS_FATAL_ERROR;
}
if (SFTP_GetAttributes(ssh->fs, buf, &out->atrb, 0, ssh->ctx->heap)
if (SFTP_GetAttributes(ssh->fs, s, &out->atrb, 0, ssh->ctx->heap)
!= WS_SUCCESS) {
WLOG(WS_LOG_SFTP, "Unable to get attribute values for %s", buf);
}
WFREE(buf, out->heap, DYNTYPE_SFTP);
}
if (!special && (WREADDIR(dir)) == NULL) {
@ -2642,37 +2652,27 @@ static int wolfSSH_SFTPNAME_readdir(WOLFSSH* ssh, WDIR* dir, WS_SFTPNAME* out,
/* attempt to get file attributes. Could be directory or have none */
{
char* buf;
int bufSz;
int tmpSz;
char r[WOLFSSH_MAX_FILENAME];
char s[WOLFSSH_MAX_FILENAME];
bufSz = out->fSz + (int)WSTRLEN(dirName) + sizeof(WS_DELIM);
buf = (char*)WMALLOC(bufSz + 1, out->heap, DYNTYPE_SFTP);
if (buf == NULL) {
return WS_MEMORY_E;
if ((WSTRLEN(dirName) + WSTRLEN(out->fName) + 2) > sizeof(r)) {
WLOG(WS_LOG_SFTP, "Path length too large");
WFREE(out->fName, out->heap, DYNTYPE_SFTP);
return WS_FATAL_ERROR;
}
buf[0] = '\0';
WSTRNCAT(buf, dirName, bufSz + 1);
tmpSz = (int)WSTRLEN(buf);
WSNPRINTF(r, sizeof(r), "%s/%s", dirName, out->fName);
/* add delimiter between path and file/dir name */
if ((tmpSz + 1 < bufSz) && (WMEMCMP(buf + tmpSz, (byte*)WS_DELIM, 1) != 0)) {
buf[tmpSz] = WS_DELIM;
buf[tmpSz+1] = '\0';
}
WSTRNCAT(buf, out->fName, bufSz + 1);
if (wolfSSH_CleanPath(ssh, buf) < 0) {
WFREE(buf, out->heap, DYNTYPE_SFTP);
if (wolfSSH_RealPath(ssh->sftpDefaultPath, r, s, sizeof(s)) < 0) {
WLOG(WS_LOG_SFTP, "Error cleaning path to get attributes");
WFREE(out->fName, out->heap, DYNTYPE_SFTP);
return WS_FATAL_ERROR;
}
if (SFTP_GetAttributes(ssh->fs, buf, &out->atrb, 0, ssh->ctx->heap)
if (SFTP_GetAttributes(ssh->fs, s, &out->atrb, 0, ssh->ctx->heap)
!= WS_SUCCESS) {
WLOG(WS_LOG_SFTP, "Unable to get attribute values for %s",
out->fName);
}
WFREE(buf, out->heap, DYNTYPE_SFTP);
}
/* Use attributes and fName to create long name */
@ -2695,7 +2695,7 @@ static int wolfSSH_SFTPNAME_readdir(WOLFSSH* ssh, WDIR* dir, WS_SFTPNAME* out,
static int wolfSSH_SFTPNAME_readdir(WOLFSSH* ssh, WDIR* dir, WS_SFTPNAME* out,
char* dirName)
{
int sz;
int sz, special = 0;
HANDLE findHandle;
char realFileName[MAX_PATH];
@ -2703,16 +2703,25 @@ static int wolfSSH_SFTPNAME_readdir(WOLFSSH* ssh, WDIR* dir, WS_SFTPNAME* out,
return WS_BAD_ARGUMENT;
}
if (*dir == INVALID_HANDLE_VALUE) {
/* special case of getting drives at "/" */
if (dirName[0] == '/' && dirName[1] == 0) {
if (ssh->driveIdx >= ssh->driveListCount)
return WS_FATAL_ERROR;
realFileName[0] = ssh->driveList[ssh->driveIdx++];
realFileName[1] = ':';
realFileName[2] = '\0';
special = 1;
}
else if (*dir == INVALID_HANDLE_VALUE) {
char name[MAX_PATH];
word32 nameLen = (word32)WSTRLEN(dirName);
if (nameLen > MAX_PATH - 3) {
if (nameLen > MAX_PATH - 2) {
WLOG(WS_LOG_SFTP, "Path name is too long.");
return WS_FATAL_ERROR;
}
WSTRNCPY(name, dirName, MAX_PATH);
WSTRNCAT(name, "\\*", MAX_PATH);
WSTRNCAT(name, "/*", MAX_PATH);
findHandle = (HANDLE)WS_FindFirstFileA(name,
realFileName, sizeof(realFileName), NULL, ssh->ctx->heap);
@ -2745,27 +2754,19 @@ static int wolfSSH_SFTPNAME_readdir(WOLFSSH* ssh, WDIR* dir, WS_SFTPNAME* out,
int bufSz;
int tmpSz;
bufSz = out->fSz + (int)WSTRLEN(dirName) + sizeof(WS_DELIM);
buf = (char*)WMALLOC(bufSz + 1, out->heap, DYNTYPE_SFTP);
bufSz = out->fSz + (int)WSTRLEN(dirName) + 2; /* /+nul */
buf = (char*)WMALLOC(bufSz, out->heap, DYNTYPE_SFTP);
if (buf == NULL) {
WFREE(out->fName, out->heap, DYNTYPE_SFTP);
return WS_MEMORY_E;
}
buf[0] = '\0';
WSTRNCAT(buf, dirName, bufSz + 1);
tmpSz = (int)WSTRLEN(buf);
/* add delimiter between path and file/dir name */
if (tmpSz + 1 < bufSz) {
buf[tmpSz] = WS_DELIM;
buf[tmpSz + 1] = '\0';
if (!special) {
WSNPRINTF(buf, bufSz, "%s/%s", dirName, out->fName);
}
WSTRNCAT(buf, out->fName, bufSz + 1);
if (wolfSSH_CleanPath(ssh, buf) < 0) {
WFREE(buf, out->heap, DYNTYPE_SFTP);
return WS_FATAL_ERROR;
else {
WSNPRINTF(buf, bufSz, "%s/", realFileName);
}
if (SFTP_GetAttributes(ssh->fs, buf, &out->atrb, 0, ssh->ctx->heap)
!= WS_SUCCESS) {
WLOG(WS_LOG_SFTP, "Unable to get attribute values for %s",
@ -2817,43 +2818,28 @@ static int wolfSSH_SFTPNAME_readdir(WOLFSSH* ssh, WDIR* dir, WS_SFTPNAME* out,
/* attempt to get file attributes. Could be directory or have none */
{
char* buf;
int bufSz;
int tmpSz;
char r[WOLFSSH_MAX_FILENAME];
char s[WOLFSSH_MAX_FILENAME];
bufSz = out->fSz + (int)WSTRLEN(dirName) + sizeof(WS_DELIM);
buf = (char*)WMALLOC(bufSz + 1, out->heap, DYNTYPE_SFTP);
if (buf == NULL) {
if ((WSTRLEN(dirName) + WSTRLEN(out->fName) + 2) > sizeof(r)) {
WLOG(WS_LOG_SFTP, "Path length too large");
WFREE(out->fName, out->heap, DYNTYPE_SFTP);
return WS_MEMORY_E;
}
buf[0] = '\0';
WSTRNCAT(buf, dirName, bufSz + 1);
tmpSz = (int)WSTRLEN(buf);
/* add delimiter between path and file/dir name */
if (tmpSz + 1 < bufSz) {
buf[tmpSz] = WS_DELIM;
buf[tmpSz+1] = '\0';
}
WSTRNCAT(buf, out->fName, bufSz + 1);
if (XSTRLEN(out->fName) == 0) {
WFREE(buf, out->heap, DYNTYPE_SFTP);
return WS_EOF;
}
if (wolfSSH_CleanPath(ssh, buf) < 0) {
WFREE(buf, out->heap, DYNTYPE_SFTP);
return WS_FATAL_ERROR;
}
WSNPRINTF(r, sizeof(r), "%s/%s", dirName, out->fName);
if (SFTP_GetAttributes(ssh->fs, buf, &out->atrb, 0, ssh->ctx->heap)
if (wolfSSH_RealPath(ssh->sftpDefaultPath, r, s, sizeof(s)) < 0) {
WLOG(WS_LOG_SFTP, "Error cleaning path to get attributes");
WFREE(out->fName, out->heap, DYNTYPE_SFTP);
return WS_FATAL_ERROR;
}
if (SFTP_GetAttributes(ssh->fs, s, &out->atrb, 0, ssh->ctx->heap)
!= WS_SUCCESS) {
WLOG(WS_LOG_SFTP, "Unable to get attribute values for %s",
out->fName);
WFREE(buf, out->heap, DYNTYPE_SFTP);
return WS_FATAL_ERROR;
}
WFREE(buf, out->heap, DYNTYPE_SFTP);
}
/* Use attributes and fName to create long name */
@ -2899,38 +2885,27 @@ static int wolfSSH_SFTPNAME_readdir(WOLFSSH* ssh, WDIR* dir, WS_SFTPNAME* out,
/* attempt to get file attributes. Could be directory or have none */
{
char* buf;
int bufSz;
int tmpSz;
char r[WOLFSSH_MAX_FILENAME];
char s[WOLFSSH_MAX_FILENAME];
bufSz = out->fSz + (int)WSTRLEN(dirName) + sizeof(WS_DELIM);
buf = (char*)WMALLOC(bufSz + 1, out->heap, DYNTYPE_SFTP);
if (buf == NULL) {
if ((WSTRLEN(dirName) + WSTRLEN(out->fName) + 2) > sizeof(r)) {
WLOG(WS_LOG_SFTP, "Path length too large");
WFREE(out->fName, out->heap, DYNTYPE_SFTP);
return WS_MEMORY_E;
return WS_FATAL_ERROR;
}
buf[0] = '\0';
WSTRNCAT(buf, dirName, bufSz + 1);
tmpSz = (int)WSTRLEN(buf);
WSNPRINTF(r, sizeof(r), "%s/%s", dirName, out->fName);
/* add delimiter between path and file/dir name */
if (tmpSz + 1 < bufSz) {
buf[tmpSz] = WS_DELIM;
buf[tmpSz+1] = '\0';
}
WSTRNCAT(buf, out->fName, bufSz + 1);
if (wolfSSH_CleanPath(ssh, buf) < 0) {
WFREE(buf, out->heap, DYNTYPE_SFTP);
if (wolfSSH_RealPath(ssh->sftpDefaultPath, r, s, sizeof(s)) < 0) {
WFREE(out->fName, out->heap, DYNTYPE_SFTP);
WLOG(WS_LOG_SFTP, "Error cleaning path to get attributes");
return WS_FATAL_ERROR;
}
if (SFTP_GetAttributes(ssh->fs, buf, &out->atrb, 0, ssh->ctx->heap)
if (SFTP_GetAttributes(ssh->fs, s, &out->atrb, 0, ssh->ctx->heap)
!= WS_SUCCESS) {
WLOG(WS_LOG_SFTP, "Unable to get attribute values for %s",
out->fName);
}
WFREE(buf, out->heap, DYNTYPE_SFTP);
}
/* Use attributes and fName to create long name */
@ -3770,7 +3745,7 @@ int wolfSSH_SFTP_RecvClose(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
int wolfSSH_SFTP_RecvRemove(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
{
word32 sz;
char* name;
char name[WOLFSSH_MAX_FILENAME];
word32 idx = 0;
int ret = WS_SUCCESS;
@ -3793,16 +3768,9 @@ int wolfSSH_SFTP_RecvRemove(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
if (sz + idx > maxSz || sz > WOLFSSH_MAX_HANDLE) {
return WS_BUFFER_E;
}
name = (char*)WMALLOC(sz + 1, ssh->ctx->heap, DYNTYPE_BUFFER);
if (name == NULL) {
return WS_MEMORY_E;
}
WMEMCPY(name, data + idx, sz);
name[sz] = '\0';
if (wolfSSH_CleanPath(ssh, name) < 0) {
ret = WS_BAD_FILE_E;
}
ret = GetAndCleanPath(ssh->sftpDefaultPath, data + idx, sz,
name, sizeof(name));
if (ret == WS_SUCCESS) {
#ifndef USE_WINDOWS_API
@ -3830,7 +3798,6 @@ int wolfSSH_SFTP_RecvRemove(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
}
/* Let the client know the results from trying to remove the file */
WFREE(name, ssh->ctx->heap, DYNTYPE_BUFFER);
if (ret != WS_SUCCESS) {
res = err;
type = WOLFSSH_FTP_FAILURE;
@ -3863,8 +3830,8 @@ int wolfSSH_SFTP_RecvRemove(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
int wolfSSH_SFTP_RecvRename(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
{
word32 sz = 0;
char* old;
char* nw;
char old[WOLFSSH_MAX_FILENAME];
char name[WOLFSSH_MAX_FILENAME];
word32 idx = 0;
int ret = WS_SUCCESS;
@ -3887,41 +3854,28 @@ int wolfSSH_SFTP_RecvRename(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
if (sz > maxSz - idx) {
ret = WS_BUFFER_E;
}
old = (char*)WMALLOC(sz + 1, ssh->ctx->heap, DYNTYPE_BUFFER);
if (old == NULL) {
ret = WS_MEMORY_E;
if (ret == WS_SUCCESS) {
ret = GetAndCleanPath(ssh->sftpDefaultPath, data + idx, sz,
old, sizeof(old));
}
if (ret == WS_SUCCESS) {
WMEMCPY(old, data + idx, sz); idx += sz;
old[sz] = '\0';
}
idx += sz;
/* get new file name */
ato32(data + idx, &sz); idx += UINT32_SZ;
if (sz > maxSz - idx) {
ret = WS_BUFFER_E;
}
nw = (char*)WMALLOC(sz + 1, ssh->ctx->heap, DYNTYPE_BUFFER);
if (nw == NULL) {
ret = WS_MEMORY_E;
}
if (ret == WS_SUCCESS) {
WMEMCPY(nw, data + idx, sz);
nw[sz] = '\0';
}
if (wolfSSH_CleanPath(ssh, old) < 0) {
ret = WS_FATAL_ERROR;
}
if (wolfSSH_CleanPath(ssh, nw) < 0) {
ret = WS_FATAL_ERROR;
ret = GetAndCleanPath(ssh->sftpDefaultPath, data + idx, sz,
name, sizeof(name));
}
if (ret == WS_SUCCESS) {
#ifndef USE_WINDOWS_API
if (WRENAME(ssh->fs, old, nw) < 0)
if (WRENAME(ssh->fs, old, name) < 0)
#else /* USE_WINDOWS_API */
if (WS_MoveFileA(old, nw, ssh->ctx->heap) == 0)
if (WS_MoveFileA(old, name, ssh->ctx->heap) == 0)
#endif /* USE_WINDOWS_API */
{
WLOG(WS_LOG_SFTP, "Error renaming file");
@ -3930,8 +3884,6 @@ int wolfSSH_SFTP_RecvRename(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
}
/* Let the client know the results from trying to rename the file */
WFREE(old, ssh->ctx->heap, DYNTYPE_BUFFER);
WFREE(nw, ssh->ctx->heap, DYNTYPE_BUFFER);
if (ret != WS_SUCCESS) {
type = WOLFSSH_FTP_FAILURE;
res = err;
@ -4519,7 +4471,6 @@ static int SFTP_GetAttributes_Handle(WOLFSSH* ssh, byte* handle, int handleSz,
#elif defined(WOLFSSH_USER_FILESYSTEM)
/* User-defined I/O support */
#else
/* @TODO can be overriden by user for portability
@ -4693,7 +4644,7 @@ int wolfSSH_SFTP_RecvFSTAT(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
int wolfSSH_SFTP_RecvSTAT(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
{
WS_SFTP_FILEATRB atr;
char* name = NULL;
char name[WOLFSSH_MAX_FILENAME];
int ret = WS_SUCCESS;
word32 sz;
@ -4713,19 +4664,11 @@ int wolfSSH_SFTP_RecvSTAT(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
return WS_BUFFER_E;
}
/* plus one to make sure is null terminated */
name = (char*)WMALLOC(sz + 1, ssh->ctx->heap, DYNTYPE_BUFFER);
if (name == NULL) {
return WS_MEMORY_E;
}
WMEMCPY(name, data + idx, sz);
name[sz] = '\0';
/* try to get file attributes and send back to client */
if (wolfSSH_CleanPath(ssh, name) < 0) {
if (GetAndCleanPath(ssh->sftpDefaultPath,
data + idx, sz, name, sizeof(name)) < 0) {
if (wolfSSH_SFTP_CreateStatus(ssh, WOLFSSH_FTP_FAILURE, reqId,
"STAT error", "English", NULL, &outSz) != WS_SIZE_ONLY) {
WFREE(name, ssh->ctx->heap, DYNTYPE_BUFFER);
return WS_FATAL_ERROR;
}
ret = WS_FATAL_ERROR;
@ -4738,7 +4681,6 @@ int wolfSSH_SFTP_RecvSTAT(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
WLOG(WS_LOG_SFTP, "Unable to get stat of file/directory");
if (wolfSSH_SFTP_CreateStatus(ssh, WOLFSSH_FTP_FAILURE, reqId,
"STAT error", "English", NULL, &outSz) != WS_SIZE_ONLY) {
WFREE(name, ssh->ctx->heap, DYNTYPE_BUFFER);
return WS_FATAL_ERROR;
}
ret = WS_BAD_FILE_E;
@ -4748,7 +4690,6 @@ int wolfSSH_SFTP_RecvSTAT(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
outSz = sz + WOLFSSH_SFTP_HEADER;
}
}
WFREE(name, ssh->ctx->heap, DYNTYPE_BUFFER);
out = (byte*)WMALLOC(outSz, ssh->ctx->heap, DYNTYPE_BUFFER);
if (out == NULL) {
@ -4782,7 +4723,7 @@ int wolfSSH_SFTP_RecvSTAT(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
int wolfSSH_SFTP_RecvLSTAT(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
{
WS_SFTP_FILEATRB atr;
char* name = NULL;
char name[WOLFSSH_MAX_FILENAME];
int ret = WS_SUCCESS;
word32 sz;
@ -4802,18 +4743,11 @@ int wolfSSH_SFTP_RecvLSTAT(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
return WS_BUFFER_E;
}
/* plus one to make sure is null terminated */
name = (char*)WMALLOC(sz + 1, ssh->ctx->heap, DYNTYPE_BUFFER);
if (name == NULL) {
return WS_MEMORY_E;
}
WMEMCPY(name, data + idx, sz);
name[sz] = '\0';
if (wolfSSH_CleanPath(ssh, name) < 0) {
if (GetAndCleanPath(ssh->sftpDefaultPath,
data + idx, sz, name, sizeof(name)) < 0) {
WLOG(WS_LOG_SFTP, "Unable to clean path");
if (wolfSSH_SFTP_CreateStatus(ssh, WOLFSSH_FTP_FAILURE, reqId,
"LSTAT error", "English", NULL, &outSz) != WS_SIZE_ONLY) {
WFREE(name, ssh->ctx->heap, DYNTYPE_BUFFER);
return WS_FATAL_ERROR;
}
ret = WS_FATAL_ERROR;
@ -4828,7 +4762,6 @@ int wolfSSH_SFTP_RecvLSTAT(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
WLOG(WS_LOG_SFTP, "Unable to get lstat of file/directory");
if (wolfSSH_SFTP_CreateStatus(ssh, WOLFSSH_FTP_FAILURE, reqId,
"LSTAT error", "English", NULL, &outSz) != WS_SIZE_ONLY) {
WFREE(name, ssh->ctx->heap, DYNTYPE_BUFFER);
return WS_FATAL_ERROR;
}
ret = WS_BAD_FILE_E;
@ -4838,7 +4771,6 @@ int wolfSSH_SFTP_RecvLSTAT(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
outSz = sz + WOLFSSH_SFTP_HEADER;
}
}
WFREE(name, ssh->ctx->heap, DYNTYPE_BUFFER);
out = (byte*)WMALLOC(outSz, ssh->ctx->heap, DYNTYPE_BUFFER);
if (out == NULL) {
@ -4926,7 +4858,7 @@ static int SFTP_SetFileAttributes(WOLFSSH* ssh, char* name, WS_SFTP_FILEATRB* at
int wolfSSH_SFTP_RecvSetSTAT(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
{
WS_SFTP_FILEATRB atr;
char* name = NULL;
char name[WOLFSSH_MAX_FILENAME];
int ret = WS_SUCCESS;
word32 sz;
@ -4953,15 +4885,11 @@ int wolfSSH_SFTP_RecvSetSTAT(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
}
/* plus one to make sure is null terminated */
name = (char*)WMALLOC(sz + 1, ssh->ctx->heap, DYNTYPE_BUFFER);
if (name == NULL) {
return WS_MEMORY_E;
}
WMEMCPY(name, data + idx, sz); idx += sz;
name[sz] = '\0';
if (wolfSSH_CleanPath(ssh, name) < 0) {
ret = WS_FATAL_ERROR;
if (GetAndCleanPath(ssh->sftpDefaultPath,
data + idx, sz, name, sizeof(name)) < 0) {
ret = WS_BUFFER_E;
}
idx += sz;
if (ret == WS_SUCCESS &&
SFTP_ParseAtributes_buffer(ssh, &atr, data, &idx, maxSz) != 0) {
@ -4979,7 +4907,6 @@ int wolfSSH_SFTP_RecvSetSTAT(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
res = ser;
ret = WS_BAD_FILE_E;
}
WFREE(name, ssh->ctx->heap, DYNTYPE_BUFFER);
if (wolfSSH_SFTP_CreateStatus(ssh, type, reqId, res, "English", NULL,
&outSz) != WS_SIZE_ONLY) {

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";
static void test_wolfSSH_RealPath(void)
struct RealPathTestCase realPathNull[] = {
{ ".", "/" },
{ "", "/" },
{ "..", "/" },
{ "../barney", "/barney" },
};
static void DoRealPathTestCase(const char* path, struct RealPathTestCase* tc)
{
struct RealPathTestCase* tc;
char testPath[128];
char checkPath[128];
word32 testCount =
(sizeof realPathTestCases)/(sizeof(struct RealPathTestCase));
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,
err = wolfSSH_RealPath(path, testPath,
checkPath, sizeof checkPath);
if (err || WSTRCMP(tc->exp, checkPath) != 0) {
printf("RealPath failure (case %u: %d)\n"
fprintf(stderr, "RealPath failure (%d)\n"
" defaultPath: %s\n"
" input: %s\n"
" expected: %s\n"
" output: %s\n", i, err,
defaultPath, tc->in, tc->exp, checkPath);
" 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)
{
word32 testCount;
word32 i;
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);