diff --git a/examples/echoserver/echoserver.c b/examples/echoserver/echoserver.c index f4d2d49..af9fd8e 100644 --- a/examples/echoserver/echoserver.c +++ b/examples/echoserver/echoserver.c @@ -1695,11 +1695,16 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args) /* if creating a ready file with port then override port to be 0 */ if (readyFile != NULL) { + #ifdef NO_FILESYSTEM + fprintf(stderr, "cannot create readyFile with no file system.\r\n"); + exit(EXIT_FAILURE); + #endif port = 0; } tcp_listen(&listenFd, &port, 1); /* write out port number listing to, to user set ready file */ if (readyFile != NULL) { + #ifndef NO_FILESYSTEM WFILE* f = NULL; int ret; ret = WFOPEN(&f, readyFile, "w"); @@ -1707,6 +1712,7 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args) fprintf(f, "%d\n", (int)port); WFCLOSE(f); } + #endif } do { diff --git a/examples/server/server.c b/examples/server/server.c index 0033cf9..82f024d 100644 --- a/examples/server/server.c +++ b/examples/server/server.c @@ -37,6 +37,9 @@ #ifdef NO_FILESYSTEM #include + #ifdef WOLFSSH_SCP + #include + #endif #endif @@ -143,6 +146,27 @@ static THREAD_RETURN WOLFSSH_THREAD server_worker(void* vArgs) int ret; thread_ctx_t* threadCtx = (thread_ctx_t*)vArgs; +#if defined(WOLFSSH_SCP) && defined(NO_FILESYSTEM) + ScpBuffer scpBufferRecv, scpBufferSend; + byte fileBuffer[1024]; + byte fileTmp[] = "wolfSSH SCP buffer file"; + + WMEMSET(&scpBufferRecv, 0, sizeof(ScpBuffer)); + scpBufferRecv.buffer = fileBuffer; + scpBufferRecv.bufferSz = 1024; + wolfSSH_SetScpRecvCtx(threadCtx->ssh, (void*)&scpBufferRecv); + + /* make buffer file to send if asked */ + WMEMSET(&scpBufferSend, 0, sizeof(ScpBuffer)); + WMEMCPY(scpBufferSend.name, "test.txt", sizeof("test.txt")); + scpBufferSend.nameSz = WSTRLEN("test.txt"); + scpBufferSend.buffer = fileTmp; + scpBufferSend.bufferSz = sizeof(fileTmp); + scpBufferSend.fileSz = sizeof(fileTmp); + scpBufferSend.mode = 0x1A4; + wolfSSH_SetScpSendCtx(threadCtx->ssh, (void*)&scpBufferSend); +#endif + if (!threadCtx->nonBlock) ret = wolfSSH_accept(threadCtx->ssh); else @@ -218,6 +242,21 @@ static THREAD_RETURN WOLFSSH_THREAD server_worker(void* vArgs) free(buf); } else if (ret == WS_SCP_COMPLETE) { printf("scp file transfer completed\n"); + #if defined(WOLFSSH_SCP) && defined(NO_FILESYSTEM) + if (scpBufferRecv.fileSz > 0) { + word32 z; + + printf("file name : %s\n", scpBufferRecv.name); + printf(" size : %d\n", scpBufferRecv.fileSz); + printf(" mode : %o\n", scpBufferRecv.mode); + printf(" mTime : %lu\n", scpBufferRecv.mTime); + printf("\n"); + + for (z = 0; z < scpBufferRecv.fileSz; z++) + printf("%c", scpBufferRecv.buffer[z]); + printf("\n"); + } + #endif } else if (ret == WS_SFTP_COMPLETE) { printf("Use example/echoserver/echoserver for SFTP\n"); } diff --git a/src/internal.c b/src/internal.c index fc26891..f1e20c2 100644 --- a/src/internal.c +++ b/src/internal.c @@ -421,8 +421,7 @@ WOLFSSH_CTX* CtxInit(WOLFSSH_CTX* ctx, byte side, void* heap) #endif /* WOLFSSH_USER_IO */ ctx->highwaterMark = DEFAULT_HIGHWATER_MARK; ctx->highwaterCb = wsHighwater; -#if defined(WOLFSSH_SCP) && !defined(WOLFSSH_SCP_USER_CALLBACKS) && \ - !defined(NO_FILESYSTEM) +#if defined(WOLFSSH_SCP) && !defined(WOLFSSH_SCP_USER_CALLBACKS) ctx->scpRecvCb = wsScpRecvCallback; ctx->scpSendCb = wsScpSendCallback; #endif /* WOLFSSH_SCP */ @@ -8744,7 +8743,7 @@ int SendChannelRequest(WOLFSSH* ssh, byte* name, word32 nameSz) } -#ifdef WOLFSSH_TERM +#if defined(WOLFSSH_TERM) && !defined(NO_FILESYSTEM) #if !defined(USE_WINDOWS_API) && !defined(MICROCHIP_PIC32) && \ !defined(NO_TERMIOS) diff --git a/src/ssh.c b/src/ssh.c index 14557d7..41d6b8c 100644 --- a/src/ssh.c +++ b/src/ssh.c @@ -872,7 +872,7 @@ int wolfSSH_connect(WOLFSSH* ssh) FALL_THROUGH; case CONNECT_CLIENT_CHANNEL_AGENT_REQUEST_SENT: - #ifdef WOLFSSH_TERM + #if defined(WOLFSSH_TERM) && !defined(NO_FILESYSTEM) if (ssh->sendTerminalRequest) { if ( (ssh->error = SendChannelTerminalRequest(ssh)) < WS_SUCCESS) { diff --git a/src/wolfscp.c b/src/wolfscp.c index b972eec..e25e652 100644 --- a/src/wolfscp.c +++ b/src/wolfscp.c @@ -47,13 +47,11 @@ #include "src/misc.c" #endif -#if defined(NO_FILESYSTEM) && !defined(WOLFSSH_SCP_USER_CALLBACKS) - #error "scp with no filesystem requires user callbacks" -#endif - +#ifndef NO_FILESYSTEM static int ScpFileIsDir(ScpSendCtx* ctx); static int ScpPushDir(ScpSendCtx* ctx, const char* path, void* heap); static int ScpPopDir(ScpSendCtx* ctx, void* heap); +#endif const char scpError[] = "scp error: %s, %d"; const char scpState[] = "scp state: %s"; @@ -1091,20 +1089,26 @@ static int ScpCheckForRename(WOLFSSH* ssh, int cmdSz) * returns WS_SUCCESS on success */ static int ParseBasePathHelper(WOLFSSH* ssh, int cmdSz) { - ScpSendCtx ctx; int ret; - WMEMSET(&ctx, 0, sizeof(ScpSendCtx)); ret = ScpCheckForRename(ssh, cmdSz); - if (ScpPushDir(&ctx, ssh->scpBasePath, ssh->ctx->heap) != WS_SUCCESS) { - WLOG(WS_LOG_DEBUG, "scp : issue opening base dir"); - } - else { - ret = ScpPopDir(&ctx, ssh->ctx->heap); - if (ret == WS_SCP_DIR_STACK_EMPTY_E) { - ret = WS_SUCCESS; /* is ok to empty the directory stack here */ + +#ifndef NO_FILESYSTEM + { + ScpSendCtx ctx; + + WMEMSET(&ctx, 0, sizeof(ScpSendCtx)); + if (ScpPushDir(&ctx, ssh->scpBasePath, ssh->ctx->heap) != WS_SUCCESS) { + WLOG(WS_LOG_DEBUG, "scp : issue opening base dir"); + } + else { + ret = ScpPopDir(&ctx, ssh->ctx->heap); + if (ret == WS_SCP_DIR_STACK_EMPTY_E) { + ret = WS_SUCCESS; /* is ok to empty the directory stack here */ + } } } +#endif /* NO_FILESYSTEM */ /* default case of directory */ return ret; @@ -1608,7 +1612,43 @@ int wolfSSH_SCP_from(WOLFSSH* ssh, const char* src, const char* dst) } -#if !defined(WOLFSSH_SCP_USER_CALLBACKS) && !defined(NO_FILESYSTEM) +#if !defined(WOLFSSH_SCP_USER_CALLBACKS) + +/* Extract file name from full path, store in fileName. + * Return WS_SUCCESS on success, negative upon error */ +static int ExtractFileName(const char* filePath, char* fileName, + word32 fileNameSz) +{ + int ret = WS_SUCCESS; + word32 fileLen; + int idx = 0, pathLen, separator = -1; + + if (filePath == NULL || fileName == NULL) + return WS_BAD_ARGUMENT; + + pathLen = (int)WSTRLEN(filePath); + + /* find last separator */ + while (idx < pathLen) { + if (filePath[idx] == '/' || filePath[idx] == '\\') + separator = idx; + idx++; + } + + if (separator < 0) + return WS_BAD_ARGUMENT; + + fileLen = pathLen - separator - 1; + if (fileLen + 1 > fileNameSz) + return WS_SCP_PATH_LEN_E; + + WMEMCPY(fileName, filePath + separator + 1, fileLen); + fileName[fileLen] = '\0'; + + return ret; +} + +#if !defined(NO_FILESYSTEM) /* for porting to systems without errno */ static INLINE int wolfSSH_LastError(void) @@ -1882,40 +1922,6 @@ int wsScpRecvCallback(WOLFSSH* ssh, int state, const char* basePath, return ret; } -/* Extract file name from full path, store in fileName. - * Return WS_SUCCESS on success, negative upon error */ -static int ExtractFileName(const char* filePath, char* fileName, - word32 fileNameSz) -{ - int ret = WS_SUCCESS; - word32 fileLen; - int idx = 0, pathLen, separator = -1; - - if (filePath == NULL || fileName == NULL) - return WS_BAD_ARGUMENT; - - pathLen = (int)WSTRLEN(filePath); - - /* find last separator */ - while (idx < pathLen) { - if (filePath[idx] == '/' || filePath[idx] == '\\') - separator = idx; - idx++; - } - - if (separator < 0) - return WS_BAD_ARGUMENT; - - fileLen = pathLen - separator - 1; - if (fileLen + 1 > fileNameSz) - return WS_SCP_PATH_LEN_E; - - WMEMCPY(fileName, filePath + separator + 1, fileLen); - fileName[fileLen] = '\0'; - - return ret; -} - static int GetFileSize(WFILE* fp, word32* fileSz) { if (fp == NULL || fileSz == NULL) @@ -2481,6 +2487,152 @@ int wsScpSendCallback(WOLFSSH* ssh, int state, const char* peerRequest, return ret; } +#else + +/* single file transfer with no filesystem */ +int wsScpRecvCallback(WOLFSSH* ssh, int state, const char* basePath, + const char* fileName, int fileMode, word64 mTime, word64 aTime, + word32 totalFileSz, byte* buf, word32 bufSz, word32 fileOffset, + void* ctx) +{ + ScpBuffer* recvBuffer; + int ret = WS_SCP_CONTINUE; + int sz; + + if (ctx == NULL) { + wolfSSH_SetScpErrorMsg(ssh, "SCP receive ctx not set"); + return WS_SCP_ABORT; + } + recvBuffer = (ScpBuffer*)ctx; + + switch (state) { + + case WOLFSSH_SCP_NEW_REQUEST: + break; + + case WOLFSSH_SCP_NEW_FILE: + /* create file */ + WMEMCPY(recvBuffer->name, fileName, WSTRLEN(fileName)); + recvBuffer->mTime = mTime; + recvBuffer->mode = fileMode; + break; + + case WOLFSSH_SCP_FILE_PART: + /* read file, or file part */ + sz = (bufSz < recvBuffer->bufferSz - recvBuffer->idx) ? + bufSz : recvBuffer->bufferSz - recvBuffer->idx; + WMEMCPY(recvBuffer->buffer + recvBuffer->idx, buf, sz); + recvBuffer->fileSz += sz; + break; + + case WOLFSSH_SCP_FILE_DONE: + recvBuffer->idx = 0; /* rewind when done */ + recvBuffer->mTime = 0; /* @TODO set time if wanted */ + break; + + case WOLFSSH_SCP_NEW_DIR: + case WOLFSSH_SCP_END_DIR: + wolfSSH_SetScpErrorMsg(ssh, + "creating a new directory not supported"); + ret = WS_SCP_ABORT; + break; + + default: + wolfSSH_SetScpErrorMsg(ssh, "invalid scp command request"); + ret = WS_SCP_ABORT; + } + + (void)totalFileSz; + (void)fileOffset; + (void)aTime; + (void)basePath; + return ret; +} + + +/* callback for single file transfer with no file system */ +int wsScpSendCallback(WOLFSSH* ssh, int state, const char* peerRequest, + char* fileName, word32 fileNameSz, word64* mTime, word64* aTime, + int* fileMode, word32 fileOffset, word32* totalFileSz, byte* buf, + word32 bufSz, void* ctx) +{ + ScpBuffer* sendBuffer= NULL; + int ret = WS_SUCCESS; + + if (ctx == NULL) { + wolfSSH_SetScpErrorMsg(ssh, "no ctx sent to hold file info"); + return WS_SCP_ABORT; + } + sendBuffer = (ScpBuffer*)ctx; + + switch (state) { + case WOLFSSH_SCP_NEW_REQUEST: + break; + + case WOLFSSH_SCP_SINGLE_FILE_REQUEST: + if (sendBuffer->buffer == NULL) { + wolfSSH_SetScpErrorMsg(ssh, "no buffer to send"); + ret = WS_SCP_ABORT; + break; + } + + *totalFileSz = sendBuffer->bufferSz; + *mTime = sendBuffer->mTime; + *aTime = sendBuffer->mTime; + *fileMode = sendBuffer->mode; + ret = ExtractFileName(peerRequest, fileName, fileNameSz); + if (WSTRLEN(fileName) != sendBuffer->nameSz || + WMEMCMP(sendBuffer->name, fileName, fileNameSz) != 0) { + wolfSSH_SetScpErrorMsg(ssh, "file name did not match"); + ret = WS_SCP_ABORT; + break; + } + + /* copy over buffer info */ + if (sendBuffer->idx >= sendBuffer->bufferSz) { + ret = WS_SCP_ABORT; + break; + } + ret = (bufSz < (sendBuffer->bufferSz - sendBuffer->idx))? + bufSz : sendBuffer->bufferSz - sendBuffer->idx; + WMEMCPY(buf, sendBuffer->buffer + sendBuffer->idx, ret); + sendBuffer->idx += ret; + + break; + + case WOLFSSH_SCP_RECURSIVE_REQUEST: + wolfSSH_SetScpErrorMsg(ssh, + "recursive request without filesystem not supported"); + ret = WS_SCP_ABORT; + break; + + case WOLFSSH_SCP_CONTINUE_FILE_TRANSFER: + /* copy over buffer info */ + if (sendBuffer->idx >= sendBuffer->bufferSz) { + ret = WS_SCP_ABORT; + break; + } + ret = (bufSz < (sendBuffer->bufferSz - sendBuffer->idx))? + bufSz : sendBuffer->bufferSz - sendBuffer->idx; + if (ret > 0) { + WMEMCPY(buf, sendBuffer->buffer + sendBuffer->idx, ret); + sendBuffer->idx += ret; + } + if (ret == 0) { /* handle case of EOF */ + ret = WS_EOF; + } + + break; + + default: + wolfSSH_SetScpErrorMsg(ssh, "bad state"); + ret = WS_SCP_ABORT; + } + (void)fileOffset; + + return ret; +} +#endif /* NO_FILESYSTME */ #endif /* WOLFSSH_SCP_USER_CALLBACKS */ #endif /* WOLFSSH_SCP */ diff --git a/wolfssh/port.h b/wolfssh/port.h index ccb2288..bb3d799 100644 --- a/wolfssh/port.h +++ b/wolfssh/port.h @@ -70,8 +70,9 @@ extern "C" { #endif #endif /* !WOLFSSH_HANDLE */ -#ifndef NO_FILESYSTEM -#ifdef WOLFSSL_NUCLEUS +#ifdef NO_FILESYSTEM + #define WS_DELIM '/' +#elif defined(WOLFSSL_NUCLEUS) #include "storage/nu_storage.h" #define WFILE int @@ -276,7 +277,6 @@ extern "C" { #endif #endif #endif -#endif /* NO_FILESYSTEM */ /* setup string handling */ #ifndef WSTRING_USER @@ -369,7 +369,7 @@ extern "C" { #endif #if (defined(WOLFSSH_SFTP) || defined(WOLFSSH_SCP)) && \ - !defined(NO_WOLFSSH_SERVER) + !defined(NO_WOLFSSH_SERVER) && !defined(NO_FILESYSTEM) #ifndef SIZEOF_OFF_T /* if not using autoconf then make a guess on off_t size based on sizeof diff --git a/wolfssh/wolfscp.h b/wolfssh/wolfscp.h index 6592f20..2fc05c1 100644 --- a/wolfssh/wolfscp.h +++ b/wolfssh/wolfscp.h @@ -52,7 +52,8 @@ extern "C" { #define DEFAULT_SCP_BUFFER_SZ DEFAULT_MAX_PACKET_SZ #endif -#if !defined(WOLFSSH_SCP_USER_CALLBACKS) && !defined(NO_FILESYSTEM) +#if !defined(WOLFSSH_SCP_USER_CALLBACKS) +#if !defined(NO_FILESYSTEM) #include #ifdef HAVE_SYS_TIME_H #include @@ -77,7 +78,19 @@ extern "C" { WDIR dir; /* dir pointer, from opendir() */ struct ScpDir* next; /* previous directory in stack */ } ScpDir; - +#else + /* Use a buffer for built in no filesystem send/recv */ + typedef struct ScpBuffer { + char name[DEFAULT_SCP_FILE_NAME_SZ]; + byte* buffer; + word64 mTime; + word32 bufferSz; /* size of "buffer" */ + word32 fileSz; /* size of file in "buffer" */ + word32 idx; /* current index into "buffer" */ + word32 nameSz; + int mode; + } ScpBuffer; +#endif /* NO_FILESYSTEM */ #endif /* WOLFSSH_SCP_USER_CALLBACKS */ enum WS_ScpFileStates {