keep a list of file handles open per session

- Track open SFTP file handles per session in a fileList, returning
  opaque session-scoped handle IDs instead of raw file descriptors.
- Resolve and validate client-supplied handle IDs via FindFileHandle.
- Free the handle list and close handles on error paths, including the
  Windows code paths.
- Drop the old raw-fd SFTP_ValidateFileHandle/STOREHANDLE handle table
  and its tests, superseded by the per-session ID lookup.
pull/1052/head
JacobBarthelmeh 2026-06-10 10:00:56 -07:00 committed by Paul Adelsbach
parent 52f6db9fe7
commit dc4df8dfdf
8 changed files with 457 additions and 487 deletions

View File

@ -143,9 +143,9 @@ static int SFTP_GetAttributes(void* fs, const char* fileName,
}
static int SFTP_GetAttributes_Handle(void* ssh, byte* handle, int handleSz,
static int SFTP_GetAttributes_Handle(void* ssh, WFD fd,
char* name, void* atr) {
(void)ssh; (void)handle; (void)handleSz; (void)name;
(void)ssh; (void)fd; (void)name; (void)atr;
return 0;
}

View File

@ -35,7 +35,6 @@
#define WOLFSSH_NO_TIMESTAMP
#define WOLFSSH_FATFS
#define WOLFSSH_STOREHANDLE
#define PRINTF printf
#define DEFAULT_WINDOW_SZ 16384
#define WOLFSSH_NO_RSA

View File

@ -140,9 +140,9 @@ static inline int SFTP_GetAttributes(void* fs, const char* fileName,
}
static inline int SFTP_GetAttributes_Handle(void* ssh, byte* handle, int handleSz,
static inline int SFTP_GetAttributes_Handle(void* ssh, WFD fd,
char* name, void* atr) {
(void)ssh; (void)handle; (void)handleSz; (void)name;
(void)ssh; (void)fd; (void)name; (void)atr;
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -1675,97 +1675,6 @@ static void TestOct2DecRejectsInvalidNonLeadingDigit(void)
wolfSSH_CTX_free(ctx);
}
#ifndef NO_WOLFSSH_SERVER
static void TestSftpRemoveHandleHeadUpdate(void)
{
WOLFSSH_CTX* ctx;
WOLFSSH* ssh;
byte firstHandle[] = { 0x01, 0x02, 0x03, 0x04 };
byte secondHandle[] = { 0x10, 0x20, 0x30, 0x40 };
int ret;
ctx = wolfSSH_CTX_new(WOLFSSH_ENDPOINT_SERVER, NULL);
AssertNotNull(ctx);
ssh = wolfSSH_new(ctx);
AssertNotNull(ssh);
ret = SFTP_AddHandleNode(ssh, firstHandle, sizeof(firstHandle), "first");
AssertIntEQ(ret, WS_SUCCESS);
ret = SFTP_AddHandleNode(ssh, secondHandle, sizeof(secondHandle), "second");
AssertIntEQ(ret, WS_SUCCESS);
ret = SFTP_RemoveHandleNode(ssh, secondHandle, sizeof(secondHandle));
AssertIntEQ(ret, WS_SUCCESS);
AssertNotNull(ssh->handleList);
AssertTrue(ssh->handleList->prev == NULL);
AssertIntEQ(ssh->handleList->handleSz, (int)sizeof(firstHandle));
AssertIntEQ(WMEMCMP(ssh->handleList->handle, firstHandle,
sizeof(firstHandle)), 0);
ret = SFTP_RemoveHandleNode(ssh, firstHandle, sizeof(firstHandle));
AssertIntEQ(ret, WS_SUCCESS);
wolfSSH_free(ssh);
wolfSSH_CTX_free(ctx);
}
static void TestSftpValidateFileHandle(void)
{
WOLFSSH_CTX* ctx;
WOLFSSH* ssh;
#ifndef USE_WINDOWS_API
byte goodHandle[sizeof(WFD)];
byte badHandle[sizeof(WFD)];
#else
byte goodHandle[sizeof(HANDLE)];
byte badHandle[sizeof(HANDLE)];
#endif
int ret;
ctx = wolfSSH_CTX_new(WOLFSSH_ENDPOINT_SERVER, NULL);
AssertNotNull(ctx);
ssh = wolfSSH_new(ctx);
AssertNotNull(ssh);
WMEMSET(goodHandle, 0x11, sizeof(goodHandle));
WMEMSET(badHandle, 0x22, sizeof(badHandle));
ret = SFTP_AddHandleNode(ssh, goodHandle, sizeof(goodHandle), "testfile");
AssertIntEQ(ret, WS_SUCCESS);
/* registered handle passes */
ret = wolfSSH_TestSftpValidateFileHandle(ssh, goodHandle, sizeof(goodHandle));
AssertIntEQ(ret, WS_SUCCESS);
/* wrong size is rejected */
ret = wolfSSH_TestSftpValidateFileHandle(ssh, goodHandle, 1);
AssertIntEQ(ret, WS_BAD_FILE_E);
/* correct size but not registered is rejected */
ret = wolfSSH_TestSftpValidateFileHandle(ssh, badHandle, sizeof(badHandle));
AssertIntEQ(ret, WS_BAD_FILE_E);
/* NULL handle pointer with valid size is rejected */
ret = wolfSSH_TestSftpValidateFileHandle(ssh, NULL, sizeof(goodHandle));
AssertIntEQ(ret, WS_BAD_FILE_E);
/* NULL ssh pointer returns WS_BAD_ARGUMENT, distinct from WS_BAD_FILE_E */
ret = wolfSSH_TestSftpValidateFileHandle(NULL, goodHandle, sizeof(goodHandle));
AssertIntEQ(ret, WS_BAD_ARGUMENT);
/* handle removed from table is rejected */
ret = SFTP_RemoveHandleNode(ssh, goodHandle, sizeof(goodHandle));
AssertIntEQ(ret, WS_SUCCESS);
ret = wolfSSH_TestSftpValidateFileHandle(ssh, goodHandle, sizeof(goodHandle));
AssertIntEQ(ret, WS_BAD_FILE_E);
wolfSSH_free(ssh);
wolfSSH_CTX_free(ctx);
}
#endif /* !NO_WOLFSSH_SERVER */
#endif /* WOLFSSH_SFTP */
#if !(defined(WOLFSSH_NO_RSA) && defined(WOLFSSH_NO_ECDSA_SHA2_NISTP256))
@ -3664,10 +3573,6 @@ int main(int argc, char** argv)
#ifdef WOLFSSH_SFTP
TestOct2DecRejectsInvalidNonLeadingDigit();
#ifndef NO_WOLFSSH_SERVER
TestSftpRemoveHandleHeadUpdate();
TestSftpValidateFileHandle();
#endif
TestSftpBufferSendPendingOutput();
#if defined(WOLFSSL_NUCLEUS) && !defined(NO_WOLFSSH_MKTIME)
TestNucleusMonthConversion();

View File

@ -724,13 +724,7 @@ WOLFSSH_LOCAL int wolfSSH_GetPath(const char* defaultPath, byte* in,
#ifndef NO_WOLFSSH_DIR
typedef struct WS_DIR_LIST WS_DIR_LIST;
#endif
typedef struct WS_HANDLE_LIST {
byte handle[WOLFSSH_MAX_HANDLE];
word32 handleSz;
char name[WOLFSSH_MAX_FILENAME];
struct WS_HANDLE_LIST* next;
struct WS_HANDLE_LIST* prev;
} WS_HANDLE_LIST;
typedef struct WS_FILE_LIST WS_FILE_LIST;
typedef struct SFTP_OFST {
word32 offset[2];
char from[WOLFSSH_MAX_FILENAME];
@ -935,7 +929,8 @@ struct WOLFSSH {
WS_DIR_LIST* dirList;
word32 dirIdCount[2];
#endif
WS_HANDLE_LIST* handleList;
word32 fileIdCount[2];
WS_FILE_LIST* fileList;
struct WS_SFTP_RECV_INIT_STATE* recvInitState;
struct WS_SFTP_RECV_STATE* recvState;
struct WS_SFTP_RMDIR_STATE* rmdirState;

View File

@ -52,33 +52,13 @@ extern "C" {
#define USE_WOLFSSH_MEMORY /* default memory handlers */
#endif /* WMALLOC_USER */
/* SFTP requires storehandle when fatfs is in use */
#ifdef WOLFSSH_FATFS
#define WOLFSSH_STOREHANDLE
#endif
#if defined (_WIN32)
#define USE_WINDOWS_API
#define _CRT_SECURE_NO_WARNINGS
#endif
#ifdef WOLFSSL_NUCLEUS
#ifndef WOLFSSH_STOREHANDLE
#define WOLFSSH_STOREHANDLE
#endif
#endif
#ifdef MICROCHIP_MPLAB_HARMONY
#ifndef WOLFSSH_STOREHANDLE
#define WOLFSSH_STOREHANDLE
#endif
#endif
#ifdef FREESCALE_MQX
#define NO_STDIO_FILESYSTEM
#ifndef WOLFSSH_STOREHANDLE
#define WOLFSSH_STOREHANDLE
#endif
#ifdef WOLFSSH_SCP
#error wolfSSH SCP not ported to MQX yet

View File

@ -174,6 +174,7 @@ struct WS_SFTPNAME {
#ifndef WOLFSSH_MAX_SFTP_RECV
#define WOLFSSH_MAX_SFTP_RECV 32768
#endif
/*
* WOLFSSH_MAX_SFTP_PACKET: Upper bound on the body size of an inbound SFTP
* request the server accepts in its steady-state receive loop
@ -189,6 +190,9 @@ struct WS_SFTPNAME {
#define WOLFSSH_MAX_SFTP_PACKET (WOLFSSH_MAX_SFTP_RW + WOLFSSH_MAX_SFTP_RECV)
#endif
#define WOLFSSH_HANDLE_ID_SZ (sizeof(word32) * 2)
/* The handle IDs are an array[2] of word32. */
/* functions for establishing a connection */
WOLFSSH_API int wolfSSH_SFTP_accept(WOLFSSH* ssh);
WOLFSSH_API int wolfSSH_SFTP_connect(WOLFSSH* ssh);
@ -291,21 +295,12 @@ WOLFSSH_LOCAL int wolfSSH_SFTP_RecvCloseDir(WOLFSSH* ssh, byte* handle,
#endif /* NO_WOLFSSH_DIR */
WOLFSSL_LOCAL int wolfSSH_SFTP_free(WOLFSSH* ssh);
WOLFSSL_LOCAL int SFTP_AddHandleNode(WOLFSSH* ssh, byte* handle,
word32 handleSz, const char* name);
WOLFSSL_LOCAL int SFTP_RemoveHandleNode(WOLFSSH* ssh, const byte* handle,
word32 handleSz);
WOLFSSH_LOCAL void wolfSSH_SFTP_ShowSizes(void);
#ifdef WOLFSSH_TEST_INTERNAL
WOLFSSH_API int wolfSSH_TestSftpBufferSend(WOLFSSH* ssh,
byte* data, word32 sz, word32 idx);
WOLFSSH_API int wolfSSH_TestSftpRecvSizeCheck(int sz);
#ifndef NO_WOLFSSH_SERVER
WOLFSSH_API int wolfSSH_TestSftpValidateFileHandle(WOLFSSH* ssh,
const byte* handle, word32 handleSz);
#endif
WOLFSSH_API int wolfSSH_TestSftpSendCap(WOLFSSH* ssh, word32 cap);
WOLFSSH_API int wolfSSH_TestSftpStallPending(WOLFSSH* ssh, word32 count);
#if defined(WOLFSSL_NUCLEUS) && !defined(NO_WOLFSSH_MKTIME)